• [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);
    }
    
  • 相关阅读:
    Android应用程序与SurfaceFlinger服务的关系概述和学习计划【转】
    Linux内核的LED设备驱动框架【转】
    电源管理-4种休眠方式状态
    linux 管道,输出重定向,后端执行
    find 和grep的区别
    linux启动脚本
    linux启动介绍
    sudo的使用
    ps aux|grep *** 解释
    php图片防盗链
  • 原文地址:https://www.cnblogs.com/chasedeath/p/14588190.html
Copyright © 2020-2023  润新知