• 【51nod 1824】染色游戏


    题目

    有 n 个红球, m 个蓝球,从中取出 x 个红球和 y 个蓝球排成一排的得分是 rx⋅by ,其中 r0=b0=1 。
    定义 f(t) 表示恰好取出 t 个球排成一排的所有可能局面的得分之和。
    两个局面相同,当且仅当这两排球的个数相等,且在对应列位置上的颜色都是相同的。
    小Q想知道,有多少 t (1≤t≤n+m) 使得 f(t) 是奇数,你能告诉他满足条件的 t2 之和吗?
    对于样例, f(1)=2,f(2)=5,f(3)=13,f(4)=28,f(5)=50,f(6)=60 ,答案是 $22+32=13 $。

    分析

    cty爆音通道 to 分治做法什么的看到我一脸懵逼
    于是只能打个FWT
    题目中的(f(t)=sum_{x+y=t}r_xb_yC_{t}^{x}),这个不用多解释。
    然后考虑如何判断(f(t))是否为奇数,
    因为只用判断奇偶,只用保留%2的结果。
    据说根据lucas定理得出,(C_{n+m}^n)为奇数,尤其尤其仅当([x and y=0])
    于是
    原式得

    [f(t)=sum_{x+y=t}r_xb_y[x and y=0] ]

    [=sum_{x+y=t}r_xb_y[x or y=t] ]

    [=sum_{x or y=t}r_xb_y[x+y=t] ]

    (bit(i))表示二进制下i的1的个数

    [=sum_{x or y=t}r_xb_y[bit(x)+bit(y)=bit(t)] ]

    然后考虑如何用FWT处理这个,
    我们让(rr_{bit(i),i}=r_i,bb_{bit(i),i}=b_i,其余为0)
    然后,对于(rr_{bit(0-20)},bb_{bit(0-20)}), 都做一次FWT,
    接着,对于(f_{bit(t),i}=sum_{bit(x)+bit(y)=bit(t)}rr_{bit(x)}bb_{bit(y)})
    最后UFWT。

    #include <cmath>
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <map>
    #include <bitset>
    const int maxlongint=2147483647;
    const int mo=1e9+7;
    const int N=2200005;
    const int M=1<<8;
    using namespace std;
    #define sqr(x) (1ll*(x)*(x))
    int n,m,r[N],b[N],fn,bit[N];
    long long ans;
    int rr[23][N>>3],bb[23][N>>3],v[4],mi[10];
    int val(int i,int j)
    {
    	return (i<<3)+7-j;
    }
    void read(int *a,int n)
    {
    	for(int i=1;i<=n;i++)
    	{
    		char c=getchar();
    		for(;c<'0' || c>'9';c=getchar());
    		a[i]=c-'0';
    	}
    }
    void FWT(int *f)
    {
    	for(int len=1;len<=3;len++)
    		for(int i=0;i<fn>>3;i++)
    			f[i]^=(f[i]&v[len])>>(1<<(len-1));
    	for(int len=2;len<=fn>>3;len<<=1)
    	{
    		int half=len>>1;
    		for(int i=0;i<half;i++)
    			for(int j=i;j<fn>>3;j+=len) f[j+half]^=f[j];
    	}
    }
    int main()
    {
    	freopen("1824.in","r",stdin);
    	freopen("1824.out","w",stdout);
    	scanf("%d%d",&n,&m);
    	fn=1<<21,v[1]=170,v[2]=204,v[3]=240;
    	mi[0]=1;
    	for(int i=1;i<=8;i++) mi[i]=mi[i-1]<<1;
    	for(int i=0;i<=fn;i++)
    		for(int x=i;x;x&=x-1,bit[i]++);
    	r[0]=b[0]=1;
    	read(r,n),read(b,m);
    	for(int i=0;i<fn>>3;i++)
    		for(int j=7;j>=0;j--) 
    			rr[bit[val(i,j)]][i]^=(r[val(i,j)]&1)*mi[j],bb[bit[val(i,j)]][i]^=(b[val(i,j)]&1)*mi[j];
    	for(int i=0;i<=20;i++) FWT(rr[i]),FWT(bb[i]);
    	for(int i=0;i<fn>>3;i++)
    	{
    		for(int k=20;k>=0;k--)
    		{
    			int tmp=0;
    			for(int j=0;j<=k;j++)
    				tmp^=bb[k-j][i]&rr[j][i];
    			rr[k][i]=tmp;
    		}
    	}
    	for(int i=0;i<=20;i++) FWT(rr[i]);
    	for(int i=0;i<fn>>3;i++)
    		for(int j=7;j>=0;j--)
    			if(val(i,j)<=n+m)
    				if(rr[bit[val(i,j)]][i]&mi[j]) ans+=sqr(val(i,j));
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    [YTU]_2911(我想放假)
    [YTU]_2907(类重载实现矩阵加法)
    [YTU]_2617(B C++时间类的运算符重载)
    [YTU]_2633( P3 数钱是件愉快的事)
    [YTU]_2444(C++习题 对象转换)
    [YTU]_2535( C++复数运算符重载(+与<<))
    [YTU]_2354 (实现复数类中的加运算符重载【C++运算符重载】)
    集训总结DAY.1(18.5.22)——KMP
    爬爬爬山
    P3803 【模板】多项式乘法(FFT)
  • 原文地址:https://www.cnblogs.com/chen1352/p/9099487.html
Copyright © 2020-2023  润新知