• 【FOI】异或问题


    题意:

    给出n个数ai 和m个操作 操作有两种

    C x y:将ax的值改为y

    Q x:求几种方案使得 b1^b2^...^bn=x(ai>=bi)

    题解:

    先推荐一个不错的题解 题目差不多 我之前就是看着题解做的

    http://hi.baidu.com/billdu/item/c749952ab2ab50c2ef10f137

    首先我们先不考虑修改 即给你n个数ai 求几种方案使得异或和为x

    为了方便起见 我们将原题的条件修改为0≤bi<ai 也就是原来的a数列中每一项都加1

    由于我们要求异或和 所以各个位不影响 不难想到 要转换成二进制做

    example1

    深蓝色的部分表示和ai的这一位一样

    绿色部分表示ai的这一位是1 而这里是0的一位

    橘黄色的部分表示不可以被随便确定的位 我们称其为“控制位”

    而浅蓝色部分表示可以被随便确定的位

    这种情况可能成为解的充要条件是没有橘黄色格子的列中的数异或起来和答案的这几位一样 答案显然是2^(浅蓝色格子数)

    状态表示:

      f[i][j][k]表示前i个数 1到j-1位有"控制位"  且第j位的异或和为k的方案数(这里的第一位是指最右边的一位)

    转移:

      为了方便 我们用递推的方法实现转移

      对于 f[i][j][k] 枚举l 表示要将第i+1个数的第l位的1转换为0 

      令xo[i][j]表示前i个数第j位的异或和

      当 l<j:nei=i+1,nej=j,nez=k^(第i+1个数的第j位),free=l-1

      当 l==j:nei=i+1,nej=j,nez=k,free=l-1

      当 l>j:nei=i+1,nej=l,nez=xo[i][l],free=j-1

      f[nei][nej][nek]+=f[i][j][k]<<free

    统计答案:

      上面提到 一种状态成为解的充要条件是没有橘黄色格子的列中的数异或起来和答案的这几位一样

      我们累加f[n][i][x的第i位] 直到xo[n][i-1]不等于x的第i-1位

    修改:

      用上面的方法每次修改都要把f数组重建 有1000次修改 每次O(n*log^2(1000)) 显然会tle

      AK想到了一种机智的方法:

      把可能变化的数放在数组的最后面 那么每次修改就最多只会影响后面的1000位

      总的时间复杂度就大概是O(1000^2*log^2(1000))

    代码:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 typedef long long ll;
     5 using namespace std;
     6 const ll N=20001,mo=1000000007;
     7 struct info{
     8     ll t,num,s;
     9     info(const ll a=0,const ll b=0,const ll c=0):
    10         t(a),num(b),s(c){}
    11 }im[N];
    12 struct inas{
    13     ll bo,x,y;
    14     inas(const ll a=0,const ll b=0,const ll c=0):
    15         bo(a),x(b),y(c){}
    16 }ask[N];
    17 ll n,m,f[N][13][2],sum[N][13],change[N];
    18 char ch;
    19 inline bool cmp(info a,info b){ return a.num<b.num; }
    20 void makechange(){
    21     sort(im+1,im+n+1,cmp);
    22     for (ll i=1;i<=n;i++) change[im[i].t]=i;
    23 }
    24 void push(ll x,ll y,ll z){
    25     ll now=im[x+1].s,nex=x+1,ney,nez,free;
    26     for (ll i=0;i<10;i++)
    27     if ((now>>i)&1){
    28         if (i<y) ney=y,nez=z^((now>>y)&1),free=i;
    29         if (i>y) ney=i,nez=sum[x][i],free=y;
    30         if (i==y) ney=i,nez=z,free=i;
    31         f[nex][ney][nez]=(f[nex][ney][nez]+(f[x][y][z]<<free)%mo)%mo;
    32     }
    33 }
    34 void makef(ll t){
    35     for (ll i=t-1;i<n;i++){
    36         for (ll j=0;j<10;j++){
    37             f[i+1][j][0]=f[i+1][j][1]=0;
    38             sum[i+1][j]=sum[i][j]^((im[i+1].s>>j)&1);
    39         }
    40         for (ll j=0;j<10;j++)
    41         for (ll k=0;k<=1;k++)
    42         if (f[i][j][k]) push(i,j,k);
    43     }
    44 }
    45 void print(ll t){
    46     ll res=0;
    47     for (ll i=9;i>=0;i--){
    48         res=(res+f[n][i][(t>>i)&1])%mo;
    49         if (sum[n][i]!=((t>>i)&1)) break;
    50     }
    51     printf("%I64d
    ",res);
    52 }
    53 int main(){
    54     scanf("%I64d%I64d",&n,&m);
    55     for (ll x,i=1;i<=n;i++){
    56         scanf("%I64d",&x);
    57         im[i]=info(i,0,x+1);
    58     }
    59     for (ll i=1,x,y;i<=m;i++){
    60         scanf("
    %c",&ch);
    61         if (ch=='Q'){
    62             scanf("%I64d",&x);
    63             ask[i]=inas(0,x,0);
    64         }else{
    65             scanf("%I64d%I64d",&x,&y);
    66             ask[i]=inas(1,x+1,y+1);
    67             ++im[x+1].num;
    68         }
    69     }
    70     makechange();
    71     f[0][0][0]=1;
    72     makef(1);
    73     for (ll i=1;i<=m;i++)
    74     if (ask[i].bo){
    75         ll now=change[ask[i].x];
    76         im[now].s=ask[i].y;
    77         makef(now);
    78     }else print(ask[i].x);
    79 }
    View Code
  • 相关阅读:
    课程笔记:——Javascript 中的预解释1
    我的博客园开通了~
    scheduling algorithm
    jQuery实现全选,全不选,反选
    jQuery实现表格选中行变色
    程序员永远的鸡血
    大家好,欢迎来到我的博客,我们一起成长,见证奇迹!
    存储过程和触发器优缺点分析
    ECStore去掉Index.php的方法
    C# 编码与解码
  • 原文地址:https://www.cnblogs.com/g-word/p/3482932.html
Copyright © 2020-2023  润新知