• Codechef AMXOR


    Problem

    Codechef

    Solution

    我们可以按位进行考虑,如果一个 (m_i) 在某一位上为1,但 (x_i) 却取了0,那么我们就称它脱离了限制,更低位可以随便乱填。也就是说,只要高位异或的方案合法,这些更低位,无论其他数怎么填,它都可以使得最终结果合法。

    那么这就变成了一个比较方便考虑的计数问题了。可以枚举第一个脱离控制的最高位,然后由于可能有多个数脱离控制,我们就选择最后一个脱离控制的数来进行计数。注意如果这一位没有脱离限制,说明所有这一位有1的都填了1,而如果这种异或方案异或出来的0,1方案与k不相同,那么就是不合法的,及时break掉。

    时间复杂度 (O(nlog v))

    Code

    #include <cstring>
    #include <cstdio>
    using namespace std;
    typedef long long ll;
    const int maxn=100010,mod=1e9+9;
    template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
    template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
    template <typename Tp> inline void read(Tp &x)
    {
        x=0;int f=0;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
        if(ch=='-') f=1,ch=getchar();
        while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
        if(f) x=-x;
    }
    int z,n,k,ans,a[maxn],lim[32],cnt[32][maxn],f[maxn][2],g[maxn];
    int pls(int x,int y){return x+y>=mod?x+y-mod:x+y;}
    int solve(int x)
    {
    	int res=0;ll tmp,sum;
    	memset(f,0,sizeof(f));
    	memset(g,0,sizeof(g));
    	f[0][0]=1;g[n+1]=1;
    	for(int i=1;i<=n;i++)
    	  for(int j=0;j<2;j++)
    	  {
    	  	if(a[i]>>x&1)
    	  	{
    	  		tmp=lim[x]-(1<<x)+1;
    	  		f[i][j]=(f[i][j]+f[i-1][j]*tmp)%mod;
    	  		tmp=(a[i]&lim[x])-(1<<x)+1;
    	  		f[i][j]=(f[i][j]+f[i-1][j^1]*tmp)%mod;
    	  	}
    	  	else
    	  	{
    	  		tmp=(a[i]&lim[x])+1;
    	  		f[i][j]=(f[i][j]+f[i-1][j]*tmp)%mod;
    	  	}
    	  }
    	for(int i=n;i;i--)
    	{
    		if(a[i]>>x&1) g[i]=(ll)g[i+1]*((a[i]&lim[x])-(1<<x)+1)%mod;
    		else g[i]=(ll)g[i+1]*((a[i]&lim[x])+1)%mod;
    	}
    	for(int i=1;i<=n;i++)
    	  if(a[i]>>x&1)
    		res=(res+(ll)f[i-1][(k>>x&1)^(cnt[x][i+1]&1)]*g[i+1])%mod;
    	return res;
    }
    int main()
    {
    	read(z);
    	lim[0]=1;
    	for(int i=1;i<=30;i++) lim[i]=lim[i-1]<<1|1;
    	while(z--)
    	{
    		read(n);ans=k=0;
    		for(int i=1;i<=n;i++){read(a[i]);k^=a[i];}
    		for(int j=30;~j;j--) cnt[j][n+1]=0;
    		for(int i=n;i;i--)
    		  for(int j=30;~j;j--)
    			cnt[j][i]=cnt[j][i+1]+(a[i]>>j&1);
    		for(int i=30;~i;i--)
    		{
    			ans=pls(ans,solve(i));
    			if((cnt[i][1]&1)!=(k>>i&1)) break;
    			ans=pls(ans,(i==0));
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    解析Zigbee技术在智能家居应用中的优缺点
    ZigBee无线网络技术在小区路灯照明系统的应用
    Zigbee技术特点
    梯度下降法-理解共轭梯度法
    感知机--理解系数向量和样本点递归
    fisher线性判别
    iso data 聚类算法
    近邻算法--类与类间最小损失函数
    聚类算法--理解最大最小距离分类
    类间距离测度方法
  • 原文地址:https://www.cnblogs.com/totorato/p/10534946.html
Copyright © 2020-2023  润新知