[数位DP] Codeforces #809C. Find a car

好题。有一个不知道怎么得出来的结论: A(x,y)=(x1) xor (y1)+1
如果知道这个了就好做了,题目转换为求 ni=0mj=0[i xor jK](i xor j+1)
然后就是数位DP了,x,y一起一位一位填, f[i][0/1][0/1][0/1] 3 0/1 分别表示 x,y,x xor y 目前是否有卡在上界的。需要维护和以及个数。很套路。

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100005,MOD=1e9+7;
typedef long long LL;
int Q,K,f1[35][2][2][2],f2[35][2][2][2]; //f1: 个数  f2: 和 
LL Calc(int n,int m){
    n--; m--; if(n<0||m<0) return 0;
    memset(f1,0,sizeof(f1));memset(f2,0,sizeof(f2)); f1[32][0][0][0]=1;
    for(int i=32;i>=2;i--)
     for(int j1=0;j1<=1;j1++)
      for(int j2=0;j2<=1;j2++)
       for(int j3=0;j3<=1;j3++) if(f1[i][j1][j2][j3]){
            int _x=(n>>i-2)&1,_y=(m>>i-2)&1,_k=(K>>i-2)&1;
            for(int t1=0;t1<=(j1?1:_x);t1++)
             for(int t2=0;t2<=(j2?1:_y);t2++){
                if(!j3&&(t1^t2)>_k) continue;
                (f1[i-1][j1|(t1<_x)][j2|(t2<_y)][j3|((t1^t2)<_k)]+=f1[i][j1][j2][j3])%=MOD;
                (f2[i-1][j1|(t1<_x)][j2|(t2<_y)][j3|((t1^t2)<_k)]+=((LL)(f2[i][j1][j2][j3]<<1)+(LL)f1[i][j1][j2][j3]*(t1^t2))%MOD)%=MOD;
            }
       }
    int res=0;
    for(int j1=0;j1<=1;j1++)
     for(int j2=0;j2<=1;j2++)
      for(int j3=0;j3<=1;j3++)
       (res+=(f2[1][j1][j2][j3]+f1[1][j1][j2][j3])%MOD)%=MOD;
    return res; 
}
int main(){
    freopen("cf809C.in","r",stdin);
    freopen("cf809C.out","w",stdout);
    scanf("%d",&Q);
    while(Q--){
        int _x1,_y1,_x2,_y2; scanf("%d%d%d%d%d",&_x1,&_y1,&_x2,&_y2,&K); K--;
        printf("%d\n",((Calc(_x2,_y2)-Calc(_x1-1,_y2)-Calc(_x2,_y1-1)+Calc(_x1-1,_y1-1))%MOD+MOD)%MOD);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值