51Nod1824 染色游戏 【Lucas定理】【FMT】【位运算】

我的FMT是在VFleaKing的论文中学到的。51Nod的评测机好恶心。

 

题目分析:

题目很明显是要你求一个类似卷积的式子。但是我们可以注意到前面具有组合数,如果拆成阶乘会很大,在模意义下你无法判断奇偶性。另辟蹊径,可以采用Lucas定理分析。

观察组合数的奇偶性,就会发现$\binom{n}{k} % 2 == 0$的充要条件是在模$2$意义下不存在$\binom{0}{1}$。这意味着$\binom{0}{0} \binom{1}{1} \binom{1}{0}$都是可以接受的。换句话说$k$是$n$的子集。注意到原来的是基础的卷积形式,所以我们要做的是对a和b的子集卷积。

全程在模$2$意义下进行,不难想到用二进制压位。

 

代码:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 
  4 #define RI register int
  5 
  6 const int maxn = (1<<20)+5;
  7 
  8 int n,m,len;
  9 int a[maxn],b[maxn];
 10 char buffer[20000000], *buf=buffer;
 11 
 12 inline void in(int &x) {
 13     while(*buf>'9' || *buf<'0') ++buf;
 14     for(x=0;*buf>='0'&&*buf<='9'; ++buf) x=x*10+*buf-'0';
 15 }
 16 
 17 inline void in1(int &x){
 18     while(*buf>'9' || *buf<'0') ++buf;
 19     x = *buf-'0';++buf;
 20 }
 21 
 22 struct Bitset{
 23     unsigned long long data[1<<14];
 24     int PrintBit(int now){
 25     int tm = now>>6,im = now&63;
 26     return (bool)(data[tm]&(1ll<<im));
 27     }
 28     void reset(int start,int len){
 29     int tm = start>>6,im = start&63;
 30     if(len >= 64){
 31         int ww = len>>6;
 32         for(RI i=0;i<ww;++i)data[tm+ww+i] ^= data[tm+i];
 33     }else{
 34         long long forw = (((1ll<<len)-1)<<im);
 35         forw = (forw&data[tm]);
 36         forw <<= len; data[tm] ^= forw;
 37     }
 38     }
 39     void SetBit(int now){
 40     int tm = now>>6,im = now&63;
 41     data[tm] |= (1ll<<im);
 42     }
 43 }am[21],bm[21],cm[21];
 44 
 45 int cnt[maxn];
 46 int f1,f2;
 47 
 48 void read(){
 49     in(n),in(m); 
 50     for(RI i=1;i<=n;++i) in1(a[i]);
 51     for(RI i=1;i<=m;++i) in1(b[i]);
 52     for(RI i=1;i<=n;++i) a[i] &= 1;
 53     for(RI i=1;i<=m;++i) b[i] &= 1;
 54     n = (n>m?n:m);m = 1;len = 0;
 55     while(m <= n) m<<=1,len++;
 56     a[0] = b[0] = 1;
 57 }
 58 
 59 void FMT(int place,int st){
 60     if(place == 0){
 61     for(RI i=1;i<m;i<<=1){
 62         int jg = m/(i<<1);
 63         for(RI j=0;j<m;j+=(jg<<1))
 64         am[st].reset(j,jg);
 65     }
 66     }else{
 67     for(RI i=1;i<m;i<<=1){
 68         int jg = m/(i<<1);
 69         for(RI j=0;j<m;j+=(jg<<1))
 70         bm[st].reset(j,jg);
 71     }
 72     }
 73 }
 74 
 75 void IFMT(int num){
 76     for(RI i=1;i<m;i<<=1){
 77      for(RI j=0;j<m;j+=(i<<1))
 78             cm[num].reset(j,i);
 79     } 
 80 }
 81 
 82 void work(){
 83     for(RI i=1;i<m;++i) { cnt[i] = cnt[i>>1]+(i&1); }
 84     for(RI i=0;i<=n;++i) {
 85     if(a[i]) am[cnt[i]].SetBit(i);
 86     if(b[i]) bm[cnt[i]].SetBit(i);
 87     }
 88     for(RI i=0;i<=len;++i){ FMT(0,i); FMT(1,i); }
 89     for(RI i=0;i<m;++i){
 90     f1 = 0,f2 = 0;
 91     for(RI j=0;j<=len;++j){
 92         f1 += (am[j].PrintBit(i)<<j);
 93         f2 += (bm[j].PrintBit(i)<<j);
 94     }
 95     int n1 = 0,n2 = 0;
 96     for(RI j=0;j<=len;++j){
 97         n1 = n1+(f1&(1<<j));
 98         if(f2&(1<<j)) n2 = (n2<<1)+1;
 99         else n2 <<=1;
100         if(cnt[n1&n2]&1) cm[j].SetBit(i);
101     }
102     }
103     for(RI i=0;i<=len;++i) IFMT(i);
104     long long ans = 0;
105     for(RI i=0;i<m;++i){
106     ans += 1ll*cm[cnt[i]].PrintBit(i)*i*i;
107     }
108     printf("%lld",ans);
109 }
110 
111 int main(){
112     fread(buffer, 1, (sizeof buffer)-1, stdin);
113     read();
114     work();
115     return 0;
116 }

 

posted @ 2018-06-19 21:36  menhera  阅读(264)  评论(0编辑  收藏  举报