bzoj 2992: Pku3986 Math teacher's homework 数位dp

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_33229466/article/details/79980855

题意

给出两个整数K,N和一个整数序列M1,M2…Mn
求满足X1 Xor X2 Xor X3…Xor Xn=k且0<=Xi<=Mi(i=1…n)的解的个数
1n50,0k,m1,m2mn2311

分析

我们按从高到底位进行处理。
假设前i位都已经处理好了,若存在一个数x[t],满足前i位中某一位比M[t]要小,那么x[t]剩下的位就可以随便填。
既然这样,那么我们就可以先不填x[t],然后让剩下的数随便填,设其最终异或和为w,那么我们只要在x[t]填上w Xor K,则可以得到一组解。
也就是说若存在一位满足其已经没有大小的限制了,那么剩下的就可以随便填。
考虑枚举这是哪一位,再枚举该位第一个没有限制的数,剩下的位置只要dp一下就好了。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

typedef long long LL;

const int N=55;
const int MOD=1000000003;

int n,m,bin[25],f[N][2],a[N];

int main()
{
    bin[0]=1;
    for (int i=1;i<=30;i++) bin[i]=bin[i-1]*2;
    scanf("%d%d",&n,&m);
    while (n||m)
    {
        for (int i=1;i<=n;i++) scanf("%d",&a[i]);
        int ans=0;
        for (int i=30;i>=0;i--)
        {
            for (int j=1;j<=n;j++)
            {
                if (!(a[j]&bin[i])) continue;
                int s=1,c=0;
                for (int k=1;k<j;k++) s=(LL)s*(a[k]%bin[i]+1)%MOD,c^=((a[k]&bin[i])>0);
                f[j][c]=s;f[j][c^1]=0;
                for (int k=j+1;k<=n;k++)
                    if (a[k]&bin[i])
                    {
                        f[k][0]=((LL)f[k-1][1]*(a[k]%bin[i]+1)%MOD+(LL)f[k-1][0]*bin[i]%MOD)%MOD;
                        f[k][1]=((LL)f[k-1][0]*(a[k]%bin[i]+1)%MOD+(LL)f[k-1][1]*bin[i]%MOD)%MOD;
                    }
                    else f[k][0]=(LL)f[k-1][0]*(a[k]%bin[i]+1)%MOD,f[k][1]=(LL)f[k-1][1]*(a[k]%bin[i]+1)%MOD;
                if (m&bin[i]) (ans+=f[n][1])%=MOD;
                else (ans+=f[n][0])%=MOD;
            }
            int c=0;
            for (int j=1;j<=n;j++) c^=a[j]&bin[i];
            if (c!=(m&bin[i])) break;
        }
        int t=0;
        for (int i=1;i<=n;i++) t^=a[i];
        if (t==m) (ans+=1)%=MOD;
        printf("%d\n",ans);
        scanf("%d%d",&n,&m);
    }
    return 0;
}
阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页