[NOI Online #3 提高组] 优秀子序列

[NOI Online #3 提高组] 优秀子序列

这个题怎么不直接取名

集合幂级数( ext{exp})

优秀的子序列中任意两个元素01位无交,这是一个标准的子集卷积形式

(varphi)的计算显然与(a_i)的卷积独立,可以线性筛/埃氏筛

暴力

可以暴力(3^{18})过,枚举时为了避免重复可以通过强制枚举的数包含最高位的1

注意(a_i=0)要特殊处理

bool Mbe;
const int N=1<<18,P=1e9+7;

int n,cnt0=1;
ll qpow(ll x,ll k=P-2){
	ll res=1;
	for(;k;k>>=1,x=x*x%P) if(k&1) res=res*x%P;
	return res;
}
int Phi[N+1],notpri[N+1];
int F[N],C[N],cnt[N];

int main(){
	Phi[1]=1;
	rep(i,2,N) if(!notpri[i]) {
		Phi[i]=i-1;
		for(int j=i+i;j<=N;j+=i) {
			notpri[j]=1;
			if(!Phi[j]) Phi[j]=j;
			Phi[j]=Phi[j]/i*(i-1);
		}
	}
	n=rd();
	rep(i,1,N-1) cnt[i]=cnt[i&(i-1)]+1;
	F[0]=1;
	rep(i,1,n) {
		int x=rd();
		if(!x) F[0]*=2,Mod1(F[0]);
		else C[x]++;
	}
	int ans=0;
	rep(S,0,N-1) {
		if(S) for(int T=S;_builtin_clz(S)==__builtin_clz(T);T=(T-1)&S) F[S]=(F[S]+1ll*F[S^T]*C[T])%P;
		ans=(ans+1ll*F[S]*Phi[S+1])%P;
	}
	printf("%d
",ans);
}

集合幂级数

就是直接套集合幂计数的( ext{exp})

同样要特殊处理(a_i=0)

const int N=1<<18,P=1e9+7;
int F[N][19],Inv[20];
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define Mod1(x) ((x>=P)&&(x-=P))
#define Mod2(x) ((x<0)&&(x+=P))
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }

char buf[200000],*p1,*p2;
#define getchar() (((p1==p2)&&(p2=(p1=buf)+fread(buf,1,200000,stdin))),*p1++)
char IO;
int rd(){
	int s=0; static char c;
	while(c=getchar(),c<48);
	do s=(s<<1)+(s<<3)+(c^'0');
	while(c=getchar(),c>47);
	return s;
}
bool Mbe;

int n,m,cnt0=1,U;
ll qpow(ll x,ll k=P-2){
	ll res=1;
	for(;k;k>>=1,x=x*x%P) if(k&1) res=res*x%P;
	return res;
}
int Phi[N+1],notpri[N+1],pri[N/4],pc;

void Exp(int *a){
	static int b[N];
	rep(i,1,n) b[i-1]=1ll*a[i]*i%P;
	rep(i,0,n-1) {
		int s=b[i];
		rep(j,1,i) s=(s+1ll*a[j]*b[i-j])%P;
		a[i+1]=1ll*s*Inv[i+1]%P;
	}
}

int main(){
	Inv[0]=Inv[1]=1;
	rep(i,2,18) Inv[i]=1ll*(P-P/i)*Inv[P%i]%P;
	n=rd();
	rep(i,1,n) {
		int x=rd(); cmax(U,x);
		if(!x) cnt0*=2,Mod1(cnt0);
		else F[x][__builtin_popcount(x)]++;
	}
	Phi[1]=1;
	for(n=1;(1<<n)<=U;)n++;
	m=1<<n;
	rep(i,2,m) {
		if(!notpri[i]) pri[++pc]=i,Phi[i]=i-1;
		for(int j=1;j<=pc && 1ll*i*pri[j]<=m;++j){
			notpri[i*pri[j]]=1;
			if(i%pri[j]==0) {
				Phi[i*pri[j]]=Phi[i]*pri[j];
				break;
			}
			Phi[i*pri[j]]=Phi[i]*(pri[j]-1);
		}
	}
	for(int i=1;i<m;i<<=1) for(int l=0;l<m;l+=i*2) for(int j=l;j<l+i;++j) rep(k,1,n) F[j+i][k]+=F[j][k],Mod1(F[j+i][k]);
	rep(i,0,m-1) Exp(F[i]);
	for(int i=1;i<m;i<<=1) for(int l=0;l<m;l+=i*2) for(int j=l;j<l+i;++j) rep(k,1,n) F[j+i][k]-=F[j][k],Mod2(F[j+i][k]);
	int ans=0;
	rep(S,1,m-1) ans=(ans+1ll*F[S][__builtin_popcount(S)]*Phi[S+1])%P;
	ans=1ll*(ans+1)*cnt0%P;
	printf("%d
",ans);
}
原文地址:https://www.cnblogs.com/chasedeath/p/14588190.html