【CF772D】Varying Kibibits FWT


【CF772D】Varying Kibibits

題意:定義函數f(a,b,c...)表示將a,b,c..的10進制下的每一位拆開,分別取最小值組成的數。如f(123,321)=121,f(530, 932, 81)=30。給你一個數集$T={a_1,a_2...a_n}$,定義函數G(x)

求$G(1)\oplus G(2)\oplus ...G(999999)$。

$1\le n \le 1000000,0\le a_i \le 999999$

題解:發現f函數就是10進制下的按位與,所以我們先對原序列進行fwt。具體地說,因為上面那個式子里有平方,所以我們要維護3個東西,a[i]表示T中i的個數,b[i]=a[i]*i,c[i]=a[i]*i*i。將這三個東西都進行fwt。

怎么統計呢?我們要求的就是一個集合的所有子集的元素的完全平方和。設當前的集合為U,我們考慮其中一個元素y的貢獻,如果$S\subseteq U-y$,那么y會在$S+y$和$U-S$里分別被統計,也就是說其貢獻是$y\times 2^{|U|-2}(b[U]+y)$。所以總的貢獻就是$2^{|U|-2}(b[U]^2+c[U])$。特判:當a[U]=1時,貢獻就是c[U];當a[U]=0時,貢獻=0。

再逆fwt回去就好了。

 

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn=1000010;
typedef long long ll;
const ll P=1000000007;
int n,len;
ll ans;
ll a[maxn],b[maxn],c[maxn],f[maxn],bt[maxn];
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
	return ret*f;
}
inline void fwt()
{
	int h,i;
	for(h=1;h<len;h*=10)
	{
		for(i=len-1;~i;i--)	if(i/h%10)
		{
			a[i-h]=(a[i-h]+a[i])%P;
			b[i-h]=(b[i-h]+b[i])%P;
			c[i-h]=(c[i-h]+c[i])%P;
		}
	}
}
inline void ufwt()
{
	int h,i;
	for(h=1;h<len;h*=10)
	{
		for(i=0;i<len;i++)	if(i/h%10)
		{
			f[i-h]=(f[i-h]-f[i]+P)%P;
		}
	}
}
int main()
{
	n=rd();
	int i;
	ll x;
	for(i=1;i<=n;i++)	x=rd(),a[x]++,b[x]=(b[x]+x)%P,c[x]=(c[x]+x*x)%P;
	len=1000000;
	fwt();
	for(bt[0]=i=1;i<=n;i++)	bt[i]=(bt[i-1]<<1)%P;
	for(i=0;i<len;i++)
	{
		if(!a[i])	continue;
		if(a[i]==1)	f[i]=c[i];
		else	f[i]=bt[a[i]-2]*(b[i]*b[i]%P+c[i])%P;
	}
	ufwt();
	for(i=0;i<len;i++)	ans^=f[i]*i;
	printf("%lld",ans);
	return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM