Codeforces #809C. Find a car 数位DP

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

dp1维护个数因为后面有个加一,dp2维护sum,注意坐标减一以及k减一

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>

using namespace std;

int q;
long long mod=1e9+7;

long long dp1[35][2][2][2];
long long dp2[35][2][2][2];

long long cal(int x,int y,int k)
{
    if(x<0 || y<0)
        return 0;

    memset(dp1,0,sizeof(dp1));
    memset(dp2,0,sizeof(dp2));

    dp1[32][1][1][1]=1;
    for(int i=32;i>=1;i--)
    {
        for(int j1=0;j1<2;j1++)
        for(int j2=0;j2<2;j2++)
        for(int j3=0;j3<2;j3++)
        if(dp1[i][j1][j2][j3])
        {
            for(int a1=0;a1<2;a1++)
            for(int a2=0;a2<2;a2++)
            {
                if(j1&&a1>((x>>i-1)&1)) continue;
                if(j2&&a2>((y>>i-1)&1)) continue;
                if(j3&&(a1^a2)>((k>>i-1)&1)) continue;

                int A=(j1&&(a1==((x>>i-1)&1)));
                int B=(j2&&(a2==((y>>i-1)&1)));
                int C=(j3&&(a1^a2)==((k>>i-1)&1));

                dp1[i-1][A][B][C]=(dp1[i-1][A][B][C]+dp1[i][j1][j2][j3])%mod;
                dp2[i-1][A][B][C]=(dp2[i-1][A][B][C]+dp2[i][j1][j2][j3]*2+(a1^a2)*dp1[i][j1][j2][j3])%mod;
            }
        }
    }
    long long ans=0;
    for(int j1=0;j1<2;j1++)
    for(int j2=0;j2<2;j2++)
    for(int j3=0;j3<2;j3++)
        ans=(ans+dp1[0][j1][j2][j3]+dp2[0][j1][j2][j3])%mod;

    return ans;
}
int main()
{
    while(~scanf("%d",&q))
    {
        while(q--)
        {
            int x1,y1,x2,y2,k;
            scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&k);
            x1--;x2--;y1--;y2--;k--;
            long long ans=(((cal(x2,y2,k)-cal(x1-1,y2,k)-cal(x2,y1-1,k)+cal(x1-1,y1-1,k))%mod)+mod)%mod;
            printf("%lld\n",ans);
        }
    }
}


 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值