zoukankan      html  css  js  c++  java
  • 51Nod1824 染色游戏 【Lucas定理】【FMT】【位运算】

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

    题目分析:

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

    观察组合数的奇偶性,就会发现$inom{n}{k} % 2 == 0$的充要条件是在模$2$意义下不存在$inom{0}{1}$。这意味着$inom{0}{0} inom{1}{1} inom{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 }
  • 相关阅读:
    设计模式第一次练习
    区间最大数
    魔方数
    螺旋数
    回文串
    最长单词
    指针的应用之学生成绩
    赛马
    突击队任务
    贪婪之骑士
  • 原文地址:https://www.cnblogs.com/Menhera/p/9201233.html
Copyright © 2011-2022 走看看