标签:long void pre for 传送门 cti return math ++
因为三个候选人实际上是一样的
所以我们只需要求出一个人的答案乘以\(3\)就行了
我们考虑A与B的比赛,和A与C的比赛
我们定义\(1\)为这个人在比赛中选了\(A\)
我们考虑每一个人的所有状态
\((0,0)\Rightarrow CBA,BCA\\(0,1)\Rightarrow BAC\\(1,0)\Rightarrow CAB\\(1,1)\Rightarrow ABC,ACB\)
对于\(f(x)\)的这个函数,实际上\(x\)为一种方案
也就是在A和B中,以及A和C中,\(f(x)\)均为1
之后我们考虑怎么求方案
我们定义\(g(x)=f(x)*f(x)\)
此时的乘法为按\(xor\)卷起来
对于一种下标,我们考虑有多少种可以构建出这个方案,
对于下标\(i\),我们定义\(i\)在二进制下0的个数为\(cnt\),方案即为\(2^{cnt}*1^{n-cnt}=2^{cnt}\)
\(ans=\sum_{i=0}^{(1<<n)-1}2^{cnt}*g_i\)
#include<iostream>
using namespace std;
const int mod=1e9+7;
const int inv=(mod+1)/2;
namespace dwt
{
	void dwtxor(int l,int r,long long *a)
	{
		if(l==r)
			return;
		int mid=(l+r)>>1;
		long long t1,t2;
		for(int i=l;i<=mid;i++)
		{
			t1=a[i];
			t2=a[i-l+1+mid];
			a[i]=(t1+t2)%mod;
			a[i-l+1+mid]=(t1-t2+mod)%mod;
		}
		dwtxor(l,mid,a);
		dwtxor(mid+1,r,a);
	}
	void idwtxor(int l,int r,long long *a)
	{
		if(l==r)
			return;
		int mid=(l+r)>>1;
		idwtxor(l,mid,a);
		idwtxor(mid+1,r,a);
		long long t1,t2;
		for(int i=l;i<=mid;i++)
		{
			t1=a[i];
			t2=a[i-l+1+mid];
			a[i]=(t1+t2)*inv%mod;
			a[i-l+1+mid]=(t1-t2+mod)*inv%mod;
		}
	}
}
using namespace dwt;
int n,len;
long long a[(1<<21)+1];
long long ans;
string s;
int fj(int x)
{
	int ret=0;
	while(x)
	{
		if(x&1)
			ret++;
		x>>=1;
	}
	return 1<<(n-ret);
}
int main()
{
	cin>>n;
	cin>>s;
	for(int i=0;i<s.length();i++)
		a[i]=s[i]-‘0‘;
	dwtxor(0,(1<<n)-1,a);
	for(int i=0;i<(1<<n);i++)
		a[i]=a[i]*a[i]%mod;
	idwtxor(0,(1<<n)-1,a);
	for(int i=0;i<(1<<n);i++)
		ans=(ans+(a[i]*fj(i))%mod)%mod;
	cout<<ans*3%mod;
	return 0;	
}
标签:long void pre for 传送门 cti return math ++
原文地址:https://www.cnblogs.com/loney-s/p/13131966.html