Winter And Snowmen

https://vjudge.net/problem/TopCoder-12891

暴力想法是:dp[i][s1][s2]前i个,第一个集合xor是s1,第二个集合xor是s2方案数O(n^3)

 

有xor

不妨按位考虑

枚举两个集合xor的LCP长度L

考虑从高到低前L位相同,第L+1位xor(X)=0,xor(Y)=1的方案数

剩下的低位就随便选择了

f[i][s][0/1][0/1]表示前i个数,前L位高位的xor和是s,第L+1位分别是0/1,0/1的方案数

每一个合法的方案都会被枚举到恰好一次。

复杂度:O(logn*n*(n/logn)=n^2)

代码:
(Topcoder还要class。。。)

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(int &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
    const int mod=1e9+7;
    const int N=2002;
    int n,m;
    int ans=0;
    int f[N][2049][2][2];
    int mo(int x,int y){
        return x+y>=mod?x+y-mod:x+y;
    }
class WinterAndSnowmen {
public:
    int getNumber(int n, int m) {
    
            int U=max(n,m);
            for(reg p=10;p>=0;--p){
                memset(f,0,sizeof f);
                f[0][0][0][0]=1;
                for(reg i=0;i<U;++i){//calc i+1
                    for(reg s=0;s<(1<<(11-p));++s){
                        for(reg l1=0;l1<=1;++l1){
                            for(reg l2=0;l2<=1;++l2){
                                int num=i+1;
                                f[i+1][s][l1][l2]=mo(f[i+1][s][l1][l2],f[i][s][l1][l2]);
                                if(i+1<=n)f[i+1][s^(num>>(p+1))][l1^((num>>p)&1)][l2]=mo(f[i+1][s^(num>>(p+1))][l1^((num>>p)&1)][l2],f[i][s][l1][l2]);
                                if(i+1<=m)f[i+1][s^(num>>(p+1))][l1][l2^((num>>p)&1)]=mo(f[i+1][s^(num>>(p+1))][l1][l2^((num>>p)&1)],f[i][s][l1][l2]);
                            }
                        }
                    }
                }
                ans=mo(ans,f[U][0][0][1]);
            }
            return ans;
    }
};

 

posted @ 2019-02-18 10:33  *Miracle*  阅读(157)  评论(0编辑  收藏  举报