Codeforces1245F (Daniel and Spring Cleaning)

题目分析:
首先明确一点,0<=l<=r<=1e9 l*r不会爆long long
所以尽管开long long就ok
由 a+b=a^b 异或是不进位的加法
如果要满足这样的性质,那么得确定一点,只要不两个位置同时为1就ok


对于这种数位统计类的问题我们一般用数位dp来做
即保存好状态,分别确定从[1,r]和[1,l-1]中满足情况的数,然后利用容斥原理来减去,
这样就可知道[l,r]区间内满足情况的的数的个数


为什么要这样搞呢???????
因为这个东西的本质是暴力穷举,即从数位高的向数位低的搜索,这样其实等效与一次暴力
枚举??????
只是我们可以设置状态,在pos以前满足一些条件的话??????
我们就可以把接下来的存下来了,就直接输出就可
这样可以看作是一次动态规划的过程???
其实本质是记忆化搜素

但是我们发现一个点,这个有两个操作数,那么就变成二维的一个操作了??????
我们可以继续用容斥的思想来搞
那么[l,r]区间满足条件的画就有 f(r,r)-2*f(l-1,r)+f(l-1,l-1)


dp的过程这个是100组,而且每次都会换不同的[l,r],建议采用把限制条件也加入的做法
这样可以快点,不会超时

如果这个i的当前为1 且j的当前为1 那么就不往下操作就可。
最后穿完所有的数还合法的方案就+1
记录一下方案数即可

/*
    题目分析:
       首先明确一点,0<=l<=r<=1e9   l*r不会爆long long
       所以尽管开long long就ok
       由       a+b=a^b     异或是不进位的加法
       如果要满足这样的性质,那么得确定一点,只要不两个位置同时为1就ok


       对于这种数位统计类的问题我们一般用数位dp来做
       即保存好状态,分别确定从[1,r]和[1,l-1]中满足情况的数,然后利用容斥原理来减去,
       这样就可知道[l,r]区间内满足情况的的数的个数


       为什么要这样搞呢???????
       因为这个东西的本质是暴力穷举,即从数位高的向数位低的搜索,这样其实等效与一次暴力
       枚举??????
       只是我们可以设置状态,在pos以前满足一些条件的话??????
       我们就可以把接下来的存下来了,就直接输出就可
       这样可以看作是一次动态规划的过程???
       其实本质是记忆化搜素

       但是我们发现一个点,这个有两个操作数,那么就变成二维的一个操作了??????
       我们可以继续用容斥的思想来搞
       那么[l,r]区间满足条件的画就有  f(r,r)-2*f(l-1,r)+f(l-1,l-1)


       dp的过程这个是100组,而且每次都会换不同的[l,r],建议采用把限制条件也加入的做法
       这样可以快点,不会超时

       如果这个i的当前为1  且j的当前为1  那么就不往下操作就可。
       最后穿完所有的数还合法的方案就+1
       记录一下方案数即可

*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <bitset>
typedef long long ll;
using namespace std;
ll dp[37][2][2];
int t;
ll l,r,L,R;

ll dfs(int pos,int lim_x,int lim_y){
    if(pos==-1) return 1;
    if(dp[pos][lim_x][lim_y]!=-1) return dp[pos][lim_x][lim_y];
    int up_x=lim_x?((int)L>>pos)&1:1;
    int up_y=lim_y?((int)R>>pos)&1:1;
    ll ans=0;
    for(int i=0;i<=up_x;i++){
        for(int j=0;j<=up_y;j++){
            if(!(i&j)){
                ans+=dfs(pos-1,lim_x&(i==up_x),lim_y&(j==up_y));
            }
        }
    }
    dp[pos][lim_x][lim_y]=ans;
    return ans;
}

ll solve(ll st,ll ed){
    if(st<0) return 0;
    L=st;R=ed;
    memset(dp,-1,sizeof(dp));
    int cnt=0;
    while(ed){ed/=2;cnt++;}
    return dfs(cnt-1,1,1);
}

int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%lld%lld",&l,&r);
        printf("%lld\n",solve(r,r)-2*solve(l-1,r)+solve(l-1,l-1));
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/pandaking/p/12013895.html
今日推荐