luoguP7468 [NOI Online 2021 提高组] 愤怒的小N

有序列01序列(s)初始为(0),每次(s)变成(soverline s)(overline s)表示(s)取反。进行无数次。

现在求:(sum_{i=0}^{n-1} s_if(i)),其中(f(x)=sum_{i=0}^{K-1}a_ix^i)

(lg nle 5*10^5)(读入二进制)

(Kle 500)


(g_0(x)=f(x))(g_{k+1}(x)=g_k(x)-g_k(x+2^k))

暴力求出(g_k(x)),最后再组合一下就能得到答案。这是(O(K^2lg n))的做法。

如果在比赛的时候打表,可以发现当(kge K)(g_k(x)=0)。于是就可以得到(O(K^3))的做法。

推导一下性质:

[g_k(x)=sum_{i=0}^{2^k-1}g_0(x+i)(-1)^{pc(i)}\ =sum_{t=0}^{K-1}x^tsum_{j=0}^{K-t-1}a_{j+t}inom{j+t}{t}sum_{i=0}^{2^k-1}(-1)^{pc(i)}i^j ]

探究(sum_{i=0}^{2^k-1}(-1)^{pc(i)}i^j)的性质。设(P_k(x)=sum p_ix^i,p_i=(-1)^{pc(i)}[0le ile 2^k-1])。代入(P_k(e^x))有:

[P_k(e^x)=sum p_ie^{ix}\ =sum p_isum_{jge 0} frac{(ix)^j}{j!}\ ]

提取([x^j])得到:([x^j]j!P_k(e^x)=sum p_i i^j)。恰好就是我们要求的东西。又有:

[P_k(x)=prod_{i=0}^{k-1}(1-x^{2^i})\ P_k(e^x)=x^kprod_{i=0}^{k-i}(-sum_{jge 1}frac{2^{ij}x^{j-1}}{j!}) ]

于是得到:如果(j<k),则([x^j]j!P_k(e^x)=0)。然后就可以解释前面的结论。


using namespace std;
#include <bits/stdc++.h>
#define L 500005
#define N 1005
#define ll long long
#define mo 1000000007
ll qpow(ll x,ll y=mo-2){
	ll r=1;
	for (;y;y>>=1,x=x*x%mo)
		if (y&1)
			r=r*x%mo;
	return r;	
}
int n,K;
ll nn;
int b[L];
ll pw[N*N],C[N][N],inv[N];
ll g[N][N],f[N];
void init(int n){
	pw[0]=1;
	for (int i=1;i<=n*n;++i)
		pw[i]=pw[i-1]*2%mo;
	for (int i=0;i<=n;++i){
		C[i][0]=1;
		for (int j=1;j<=i;++j)
			C[i][j]=(C[i-1][j-1]+C[i-1][j])%mo;
	}
	inv[1]=1;
	for (int i=2;i<=n;++i)
		inv[i]=(mo-mo/i)*inv[mo%i]%mo;
}
ll getsum0(){
	static ll S[N][N];
	S[0][0]=1;
	for (int i=1;i<=K;++i)
		for (int j=1;j<=i;++j)
			S[i][j]=(S[i-1][j-1]+j*S[i-1][j])%mo;
	ll sum=0;
	for (int k=0;k<K;++k){
		ll tmp=0;
		for (int i=0;i<=k;++i){
			ll pro=1;
			for (int j=nn-i;j<=nn;++j)
				pro=pro*j%mo;
			(tmp+=S[k][i]*inv[i+1]%mo*pro)%=mo;
		}
		(sum+=tmp*g[0][k])%=mo;
	}
	return sum;
}
int main(){
	static char str[L];
	scanf("%s",str);
	n=strlen(str);
	for (int i=0;i<n;++i)
		b[i]=str[n-1-i]-'0';
	for (int i=0,w=1;i<n;++i,w=w*2%mo)
		(nn+=b[i]*w)%=mo;
	scanf("%d",&K);
	for (int i=0;i<K;++i)
		scanf("%d",&g[0][i]);
	init(K);
	ll sum0=getsum0(),sum1=0;
	for (int k=0;k<K;++k)
		for (int j=0;j<K;++j){
			ll sum=0;
			for (int i=j;i<K;++i)
				(sum+=g[k][i]*pw[k*(i-j)]%mo*C[i][j])%=mo;
			g[k+1][j]=(g[k][j]-sum+mo)%mo;
		}
	int c=1;
	for (int k=n-1,of=0;k>=0;--k)
		if (b[k]){
			if (k<K){
				ll sum=0;
				for (int i=0;i<K;++i)
					(sum+=g[k][i]*qpow(of,i))%=mo;
				sum1+=sum*c;
			}
			c*=-1;
			(of+=qpow(2,k))%=mo;
		}
	ll ans=(sum0-sum1)*qpow(2)%mo;
	ans=(ans+mo)%mo;
	printf("%lld
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/jz-597/p/14586665.html