HDU 3693 Math teacher's homework(数位dp)

Math teacher's homework

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 646    Accepted Submission(s): 248


 

Problem Description

Mr. Furion is a math teacher. His students are very lazy and they do not like to do their homework. One day, Mr. Furion decides to give them a special problem in order to see whether his students are talents in math or they are just too lazy to do their homework. The problem is:


Given an integer k, n integers m1,m2…mn, and a formula below: 

X1 xor X2 xor X3… xor Xn = k 

Please figure out that how many integral solutions of the formula can satisfy:

0<=Xi<=mi (i=1…n)

 

Input

There are at most 100 test cases.

The first line of each test case contains two integers n and k. The second line of each test contains n integers: m1,m2…mn. The meaning of n,k, m1,m2…mn are described above. (1<=n<=50,0<=k,m1,m2…mn<=2^31-1 )

The input is ended by “0 0”.

 

Output

You should output a integer for each test case, which is the number of solutions. As the number might be very large, you should only output the number modulo 1000000003.

扫描二维码关注公众号,回复: 5932882 查看本文章

 

Sample Input

 

11 2047 1024 512 256 128 64 32 16 8 4 2 1 10 2047 1024 512 256 128 64 32 16 8 4 2 0 0

 

Sample Output

 

1 0

题意:给你n(n<=50)个数ai(ai<=2^31-1),再给你一个数k(k<=2^31-1),求x1^x2^...^xn=k(0<=xi<=ai)的解的总数。

思路:

考虑数位dp。

dp[i][pre][len]表示到当前xi,最低位为第len位的前缀为pre的答案总数。

我们枚举ai为1的那些位(把xi的这一位赋为0,那么低位就可以随便取了),考虑xi与ai的最长公共前缀。

因此可得状态转移方程:

dp[i][pre][len]=\sum_{j=31}^{0}\left ( dp[i+1][pre\bigoplus cur][max(j,len)]*2^{min(j,len)} \right )

cur表示的是xi的所有可能前缀。j表示cur的前缀长度。

但是第二维的数组显然开不了那么大。

仔细观察dp的过程可以发现,如果i和len确定时,当前的pre除了第len位都是可以确定的,因此第二维就可以优化成2了。

代码:

#include<iostream>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<string>
#include<queue>
#include<vector>
#include<map>
#define ll long long
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(register int i=(a);i<=(b);++i)
#define dep(i,a,b) for(register int i=(a);i>=(b);--i)
using namespace std;
const int maxn=55;
const ll mo=1000000003;
int n,m,k,mm;
int tmp,cnt,ans;
ll dp[maxn][maxn][2];
ll po[maxn];
int a[maxn];
ll dfs(int i,int pre,int len)
{
    int now=0,k;
    pre&=(~((1<<len)-1));
    if(i==n+1) return !pre;
    if(pre&(1<<len)) k=1;
    else k=0;
    if(dp[i][len][k]!=-1) return dp[i][len][k];
    ll sum=0;
    dep(j,31,0)
    if(a[i]&(1<<j)){
        sum+=dfs(i+1,pre^now,max(j,len))*po[min(j,len)]%mo;
        sum%=mo;
        now|=(1<<j);
    }
    dp[i][len][k]=sum;
    return dp[i][len][k];
}
int main()
{
    po[0]=1;
    rep(i,1,maxn-1)
    po[i]=(po[i-1]<<1)%mo;
    int T,cas=1;
    while(scanf("%d%d",&n,&m)!=EOF&&(n||m))
    {
        memset(dp,-1,sizeof(dp));
        rep(i,1,n)
        {
            scanf("%d",&a[i]);
            a[i]++;
        }
        ll ans=dfs(1,m,0);
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/LSD20164388/article/details/89277739