【2020省选模拟】题解

T1:

之前 c f cf cf的一道原题
容斥 0 / 1 0/1 0/1后发现只和 1 1 1连续段有关
枚举拆分后或卷积即可

#include
using namespace std;
#define cs const
#define pb push_back
#define pii pair
#define fi first
#define se second
#define ll long long 
#define bg begin

namespace IO{

cs int rlen=1<<20|1;
char ibuf[rlen],*ib,*ob;
inline char gc(){
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,rlen,stdin));
	return (ib==ob)?EOF:*ib++;
}

inline int read(){
	char ch=gc();
	int res=0;bool f=0;
	while(!isdigit(ch))f=ch=='-',ch=gc();
	while(isdigit(ch))res=(res*10)+(ch^48),ch=gc();
	return f?-res:res;
}
inline int readstring(char *s){
	int top=0;char ch=gc();
	while(isspace(ch))ch=gc();
	while(!isspace(ch)&&ch!=EOF)s[++top]=ch,ch=gc();
	s[top+1]='\0';return top;
}

}
using IO::read;
using IO::readstring;

template<typename tp>inline void chemx(tp &a,tp b){(a<b)?(a=b):0;}
template<typename tp>inline void chemn(tp &a,tp b){(a>b)?(a=b):0;}

cs int N=19,M=(1<<17)|5;
ll dp[M][N],fac[N],f[M],v[N][M],ans[M];
int a[N][N],n,lim,cnt[M];
char str[N];
vector<int>divi;
map<vector<int>,ll>mp;
inline void fwt(ll *f){
	for(int mid=1;mid<lim;mid<<=1)
	for(int i=0;i<lim;i+=mid<<1)
	for(int j=0;j<mid;j++)
	f[i+j+mid]+=f[i+j];
}
inline void ifwt(ll *f){
	for(int mid=1;mid<lim;mid<<=1)
	for(int i=0;i<lim;i+=mid<<1)
	for(int j=0;j<mid;j++)
	f[i+j+mid]-=f[i+j];
}
inline void calc(){
	ll res=f[lim-1];
	for(int i=0;i<lim-1;i++)res=(cnt[i^(lim-1)]&1)?res-f[i]:res+f[i];
	mp[divi]=res;
}
void dfs(int num,int lst){
	if(num>n)return;
	if(num==n){
		return calc();
	}
	vector<ll>pre(lim);
	for(int i=0;i<lim;i++)pre[i]=f[i];
	for(int i=lst;i<=n-num;i++){
		for(int j=0;j<lim;j++)f[j]=pre[j]*v[i][j];
		divi.pb(i),dfs(num+i,i);
		divi.pop_back();
	}
}
void fmt(ll *f,int lim){
	for(int mid=1;mid<lim;mid<<=1)
	for(int i=0;i<lim;i+=mid<<1)
	for(int j=0;j<mid;j++)
	f[i+j]-=f[i+j+mid];
}
int main(){
	n=read(),lim=1<<n;
	for(int i=0;i<n;i++){
		readstring(str);
		for(int j=0;j<n;j++)a[i][j]=str[j+1]-'0';
	}
	for(int i=1;i<lim;i++)cnt[i]=cnt[i>>1]+(i&1);
	fac[0]=1;
	for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i;
	for(int i=0;i<n;i++)dp[1<<i][i]=1;
	for(int s=1;s<lim;s++)
	for(int i=0;i<n;i++)if(((s>>i)&1)&&dp[s][i]){
		ll vl=dp[s][i];
		for(int j=0;j<n;j++)if(!((s>>j)&1)&&a[i][j]==1)
		dp[s|(1<<j)][j]+=vl;
	}
	for(int s=1;s<lim;s++)
	for(int i=0;i<n;i++)if(dp[s][i])v[cnt[s]][s]+=dp[s][i];
	f[0]=1,fwt(f);
	for(int i=1;i<=n;i++)fwt(v[i]);
	dfs(0,1);
	for(int i=0;i<(lim>>1);i++){
		vector<int>d;int cnt=0;
		for(int j=0;j<n;j++){
			cnt++;
			if(((i>>j)&1)==0)d.pb(cnt),cnt=0;
		}sort(d.bg(),d.end());
		ans[i]=mp[d];
	}
	fmt(ans,lim>>1);
	int T=read();
	while(T--){
		readstring(str);
		int res=0;
		for(int i=1;i<n;i++)res=(res*2)+(str[i]-'0');
		cout<<ans[res]<<'\n';
	}return 0;
}

T2:

z x y zxy zxy教育

考虑对 r r r以及之后所有前缀计算答案
对于一个前缀 i i i,答案就是 i − l e n + 1 i-len+1 ilen+1这样的形式
那么最后答案可以表示成 k ∗ ( r − l + 1 ) + b k*(r-l+1)+b k(rl+1)+b这样
而不同的后缀只需要考虑后缀自动机 d a g dag dag上后继即可

树剖把倍增吊起来打

#include
using namespace std;
#define cs const
#define pb push_back
#define pii pair
#define fi first
#define se second
#define ll long long
#define bg begin

namespace IO{

cs int rlen=1<<20|1;
char ibuf[rlen],*ib,*ob;
inline char gc(){
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,rlen,stdin));
	return (ib==ob)?EOF:*ib++;
}
inline int read(){
	char ch=gc();
	int res=0;bool f=0;
	while(!isdigit(ch))f=ch=='-',ch=gc();
	while(isdigit(ch))res=(res*10)+(ch^48),ch=gc();
	return f?-res:res;
}
inline int readstring(char *s){
	int top=0;char ch=gc();
	while(isspace(ch))ch=gc();
	while(!isspace(ch)&&ch!=EOF)s[++top]=ch,ch=gc();
	s[top+1]='\0';return top;
}

}
using IO::read;
using IO::readstring;

cs int N=800005;
int n,q;
char str[N];
int nxt[N][26],tot=1,last=1,fa[N],len[N],ps[N];
ll k[N],b[N],s[N];
inline void insert(int c,int id){
	int cur=++tot,p=last;last=cur;
	len[cur]=len[p]+1,ps[id]=cur;
	for(;p&&!nxt[p][c];p=fa[p])nxt[p][c]=cur;
	if(!p)fa[cur]=1;
	else{
		int q=nxt[p][c];
		if(len[p]+1==len[q])fa[cur]=q;
		else{
			int clo=++tot;
			fa[clo]=fa[q],len[clo]=len[p]+1;
			memcpy(nxt[clo],nxt[q],sizeof(nxt[q]));
			for(;p&&nxt[p][c]==q;p=fa[p])nxt[p][c]=clo;
			fa[cur]=fa[q]=clo;
		}
	}
}
int buc[N],rk[N];
int sz[N],hs[N],in[N],idx[N],top[N],dfn;
inline void build(){
	for(int i=1;i<=tot;i++)buc[len[i]]++;
	for(int i=1;i<=tot;i++)buc[i]+=buc[i-1];
	for(int i=tot;i>=1;i--)rk[buc[len[i]]--]=i;
	for(int i=tot;i>=1;i--){
		int u=rk[i];
		k[u]=-1,b[u]=s[u]+len[u]+1;
		if(fa[u])s[fa[u]]+=s[u]+len[u]-len[fa[u]];
	}
	for(int i=tot;i>=1;i--){
		int p=rk[i];
		for(int c=0;c<26;c++){
			int v=nxt[p][c];
			if(v){
				k[p]+=k[v],b[p]+=b[v]+k[v];
			}
		}
	}
	for(int i=tot;i>=1;i--){
		int u=rk[i];sz[u]++; 
		sz[fa[u]]+=sz[u];
		if(sz[u]>sz[hs[fa[u]]])hs[fa[u]]=u;
	}
	for(int i=1;i<=tot;i++){
		int u=rk[i];
		if(!top[u]){
			for(int p=u;p;p=hs[p])
			idx[in[p]=++dfn]=p,top[p]=u;
		}
	}
}
inline ll query(int l,int r){
	int le=r-l+1,u=ps[r];
	while(len[fa[top[u]]]>=le)u=fa[top[u]];
	l=in[top[u]],r=in[u];int res=r;
	while(l<=r){
		int mid=(l+r)>>1;
		if(len[idx[mid]]>=le)r=mid-1,res=mid;
		else l=mid+1;
	}u=idx[res];
	return k[u]*le+b[u];
}
int main(){
	#ifdef Stargazer
	freopen("lx.in","r",stdin);
	#endif
 
	n=read(),q=read();
	readstring(str);
	for(int i=1;i<=n;i++)insert(str[i]-'a',i);
	build();
	while(q--){
		int l=read(),r=read();
		cout<<query(l,r)<<'\n';
	}return 0;
}

T3:

枚举最大值的位置可以得到一个显然的 D P DP DP方程
直接 m t t mtt mtt可过
转成点值计算可以做到更优秀

#include
using namespace std;
#define cs const
#define pb push_back
#define pii pair
#define fi first
#define se second
#define ll long long 
#define bg begin

namespace IO{

cs int rlen=1<<20|1;
char ibuf[rlen],*ib,*ob;
inline char gc(){
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,rlen,stdin));
	return (ib==ob)?EOF:*ib++;
}
inline int read(){
	char ch=gc();
	int res=0;bool f=0;
	while(!isdigit(ch))f=ch=='-',ch=gc();
	while(isdigit(ch))res=(res*10)+(ch^48),ch=gc();
	return f?-res:res;
}

}
using IO::read;
template<typename tp>inline void chemx(tp &a,tp b){return (a<b)?(a=b):0;}
template<typename tp>inline void chemn(tp &a,tp b){return (a>b)?(a=b):0;}

int mod;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(int a,int b){return a<b?a-b+mod:a-b;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline void Add(int &a,int b){a=a+b>=mod?a+b-mod:a+b;}
inline void Dec(int &a,int b){a=a<b?a-b+mod:a-b;}
inline void Mul(int &a,int b){a=(ll)a*b%mod;}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,Mul(a,a))(b&1)&&(Mul(res,a),1);return res;}
typedef vector<int> poly;
typedef double db;
cs int N=201;
void write(poly f){
	for(int i=0;i<f.size();i++)cout<<f[i]<<" ";puts("");
}
int n,k,C[N][N];
poly f[N];
namespace Poly{
	struct plx{
		db x,y;
		plx(db _x=0,db _y=0):x(_x),y(_y){}
		inline plx operator +(cs plx &b){
			return plx(x+b.x,y+b.y);
		}
		inline plx operator -(cs plx &b){
			return plx(x-b.x,y-b.y);
		}
		inline plx operator *(cs plx &b){
			return plx(x*b.x-y*b.y,x*b.y+y*b.x);
		}
		inline plx operator *(cs db &b){
			return plx(x*b,y*b);
		}
		inline plx operator /(cs db &b){
			return plx(x/b,y/b);
		}
		inline plx conj()cs{return plx(x,-y);}
	};
	cs int MM=(1<<16)|1,T=(1<<15)-1;
	plx *w[17];int rev[MM];
	cs db pi=acos(-1);
	inline void init_rev(int lim){
		for(int i=0;i<lim;i++)rev[i]=(rev[i>>1]>>1)|((i&1)*(lim>>1));
	}
	inline void init_w(cs int C=16){
		for(int i=1;i<=C;i++)w[i]=new plx[(1<<(i-1))|1];
		w[C][0]=plx(1,0);
		for(int i=1,l=1<<(C-1);i<l;i++)
		w[C][i]=plx(cos(i*pi/l),sin(i*pi/l));
		for(int i=C-1;i;i--)
		for(int j=0,l=1<<(i-1);j<l;j++)w[i][j]=w[i+1][j<<1];
	}
	inline void fft(plx *f,int lim,int kd){
		for(int i=0;i<lim;i++)if(i>rev[i])swap(f[i],f[rev[i]]);
		plx a0,a1;
		for(int mid=1,l=1;mid<lim;mid<<=1,l++)
		for(int i=0;i<lim;i+=mid<<1)
		for(int j=0;j<mid;j++)
		a0=f[i+j],a1=f[i+j+mid]*w[l][j],f[i+j]=a0+a1,f[i+j+mid]=a0-a1;
		if(kd==-1){
			reverse(f+1,f+lim);
			for(int i=0;i<lim;i++)f[i]=f[i]/lim;
		}
	}
	plx a[MM],b[MM],c[MM],d[MM];
	inline poly mul(poly A,poly B,int mov){
		int deg=A.size()+B.size()-1,lim=1;
		while(lim<deg)lim<<=1;init_rev(lim);
		for(int i=0;i<A.size();i++)a[i]=plx(A[i]&T,A[i]>>15);
		for(int i=A.size();i<lim;i++)a[i].x=a[i].y=0,a[i]=plx();
		for(int i=0;i<B.size();i++)b[i]=plx(B[i]&T,B[i]>>15);
		for(int i=B.size();i<lim;i++)b[i].x=b[i].y=0,b[i]=plx();
		fft(a,lim,1),fft(b,lim,1);plx da,db,dc,dd;
		for(int i=0,j;i<lim;i++){
			j=(lim-i)&(lim-1);
			da=(a[i]+a[j].conj())*plx(0.5,0);
			db=(a[j].conj()-a[i])*plx(0,0.5);
			dc=(b[i]+b[j].conj())*plx(0.5,0);
			dd=(b[j].conj()-b[i])*plx(0,0.5);
			c[i]=(da*dc)+(da*dd*plx(0,1)),d[i]=(db*dc)+(db*dd*plx(0,1));
		}poly res(deg+mov,0);
		fft(c,lim,-1),fft(d,lim,-1);
		for(int i=0;i<deg;i++){
			ll da=(ll)(c[i].x+0.5)%mod,db=(ll)(c[i].y+0.5)%mod,dc=(ll)(d[i].x+0.5)%mod,dd=(ll)(d[i].y+0.5)%mod;
			res[i+mov]=(da+(db<<15)+(dc<<15)+(dd<<30))%mod;
		}return res;
	}
	inline poly operator *(poly a,int b){
		for(int i=0;i<a.size();i++)Mul(a[i],b),assert(a[i]>=0&&a[i]<mod);
		return a;
	}
	inline poly operator +(poly a,poly b){
		if(a.size()<b.size())a.resize(b.size());
		for(int i=0;i<b.size();i++)Add(a[i],b[i]),assert(a[i]>=0&&a[i]<mod);
		return a;
	}
}
using namespace Poly;
inline void init_c(){
	for(int i=0;i<N;i++){
		C[i][0]=C[i][i]=1;
		for(int j=1;j<i;j++)
		C[i][j]=add(C[i-1][j],C[i-1][j-1]);
		
	}
}
inline void solve(){
	f[0].pb(1);f[1].pb(0),f[1].pb(1);
	for(int i=2;i<N;i++){
		for(int k=0;k<(i+1)/2;k++){
			f[i]=f[i]+Poly::mul(f[k],f[i-k-1],min(k+1,i-k))*mul(C[i-1][k],(k+1==i-k)?1:2);
		}
	}
}
int main(){
	scanf("%d",&mod);
	init_w(),init_c();
	solve();
	while(scanf("%d%d",&n,&k)!=EOF){
		if(k>=f[n].size())puts("0");
		else cout<<f[n][k]<<'\n';
	}
}

你可能感兴趣的:(【2020省选模拟】题解)