模擬賽20200208【概率生成函數,NTT優化DP,同構(本質匹配)後綴數組】

T1:

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

題解:

考試的時候相當轉化爲多項式,然後就不會了。。
題解:求無窮項的多項式是可以由遞推關係解的!用分式多項式表示就行了!
在這裏插入圖片描述
在這裏插入圖片描述
std維護了多項式,但是由於最後只需要F1(z)=zF(z),F2(z2)=z4F(z2)+z2F(z2)F_1(z)=zF'(z),F_2(z^2)=z^4F''(z^2)+z^2F'(z^2)
維護fi(z),fi(z),fi(z2),fi(z2),fi(z2)f_i(z),f_i'(z),f_i(z^2),f_i'(z^2),f_i''(z^2)的值即可。
轉移時的求導比較冗長。
Code:

#include<bits/stdc++.h>
#define maxn 55
using namespace std;
const int mod = 998244353;
int n,z,f,z2,c[maxn][maxn],p[maxn],f0[maxn],f1[maxn],g0[maxn],g1[maxn],g2[maxn];
inline int Pow(int a,int b){
	int s=1; for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) s=1ll*s*a%mod;
	return s;
}
inline int Inv(int x){return Pow(x,mod-2);}
int main()
{
	freopen("capitalism.in","r",stdin);
	freopen("capitalism.out","w",stdout);
	scanf("%d%d%d",&n,&z,&f),z2=1ll*z*z%mod;
	for(int i=1;i<n;i++)
		for(int j=i+1;j<=n;j++)
			scanf("%d",&c[i][j]),p[j]=(p[j]+c[i][j])%mod;
	f0[1]=1ll*f*Inv((1-(1ll-f)*z)%mod)%mod;//F(z)
	f1[1]=1ll*f*(1-f)%mod*Pow(Inv((1-(1ll-f)*z)%mod),2)%mod;//F'(z)
	g0[1]=1ll*f*Inv((1-(1ll-f)*z2)%mod)%mod;//F(z^2)
	g1[1]=1ll*f*(1-f)%mod*Pow(Inv((1-(1ll-f)*z2)%mod),2)%mod;//F'(z^2)
	g2[1]=2ll*f*(1-f)%mod*(1-f)%mod*Pow(Inv((1-(1ll-f)*z2)%mod),3)%mod;//F''(z^2)
	for(int i=2;i<=n;i++){
		p[i]=1-p[i];
		int d1=Inv((1-1ll*p[i]*z)%mod),d2=Inv((1-1ll*p[i]*z2)%mod);
		for(int j=1;j<i;j++){
			f0[i]=(f0[i]+1ll*z*c[j][i]%mod*f0[j]%mod*d1)%mod;
			f1[i]=(f1[i]+(1ll*c[j][i]*f0[j]+1ll*z*c[j][i]%mod*f1[j])%mod*d1+1ll*z*p[i]%mod*c[j][i]%mod*f0[j]%mod*d1%mod*d1)%mod;
			g0[i]=(g0[i]+1ll*z2*c[j][i]%mod*g0[j]%mod*d2)%mod;
			g1[i]=(g1[i]+(1ll*c[j][i]*g0[j]+1ll*z2*c[j][i]%mod*g1[j])%mod*d2+1ll*z2*p[i]%mod*c[j][i]%mod*g0[j]%mod*d2%mod*d2)%mod;
			g2[i]=(g2[i]+c[j][i]*((2ll*g1[j]+1ll*z2*g2[j]%mod)*d2%mod+2ll*p[i]*(1ll*z2*g1[j]%mod*Pow(d2,2)%mod+1ll*g0[j]*Pow(d2,3)%mod)%mod))%mod;
		}
	}
	printf("%d\n",((1ll*z2*z2%mod*g2[n]+1ll*z2*g1[n]-Pow(1ll*z*f1[n]%mod,2))%mod+mod)%mod);
}

std用vector<pair>存了多項式的次數和係數,分別維護分子多項式和分母多項式:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
typedef long long LL;
const int N=55,M=998244353;
int n,z,f[N],c[N][N];

typedef vector<pair<int,int> > poly;

poly X,u,v,u1,v1,u2,v2;
poly Num[N],Den[N],tmps,tmpa,tmpm,tmpd,tmpc;

int fpw(int a,int b,const int c=M)
{
	int s=1;
	for(;b;b>>=1,a=(LL)a*a%c)
		if(b&1)s=(LL)s*a%c;
	return s;
}

int inv(int a,const int b=M)
{
	return fpw(a,b-2,b);
}

void simplify(poly &p)
{
	sort(p.begin(),p.end());
	tmps.clear();
	for(int i=0;i<p.size();i++)
	{
		if(tmps.empty()||tmps.back().first!=p[i].first)
			tmps.push_back(p[i]);
		else
			(tmps.back().second+=p[i].second)%=M;
		if(tmps.back().second==0)tmps.pop_back();
	}
	p=tmps;
}

poly operator+(const poly &a,const poly &b)
{
	tmpa.clear();
	for(int i=0;i<a.size();i++)
		tmpa.push_back(a[i]);
	for(int i=0;i<b.size();i++)
		tmpa.push_back(b[i]);
	simplify(tmpa);
	return tmpa;
}

poly operator-(const poly &a,const poly &b)
{
	tmpa.clear();
	for(int i=0;i<a.size();i++)
		tmpa.push_back(a[i]);
	for(int i=0;i<b.size();i++)
		tmpa.push_back(make_pair(b[i].first,M-b[i].second));
	simplify(tmpa);
	return tmpa;
}

poly operator*(const poly &a,const poly &b)
{
	tmpm.clear();
	for(int i=0;i<a.size();i++)
		for(int j=0;j<b.size();j++)
			tmpm.push_back(make_pair(a[i].first+b[j].first,(LL)a[i].second*b[j].second%M));
	simplify(tmpm);
	return tmpm;
}

poly operator*(const poly &a,const int &b)
{
	tmpc=a;
	for(int i=0;i<tmpc.size();i++)
		tmpc[i].second=(LL)tmpc[i].second*b%M; 
	return tmpc;
}

poly derivative(const poly &a)
{
	tmpd.clear();
	for(int i=0;i<a.size();i++)
		if(a[i].first!=0)
			tmpd.push_back(make_pair(a[i].first-1,(LL)a[i].second*a[i].first%M));
	return tmpd;
}

int calc(const poly &a,int x)
{
	int res=0;
	for(int i=0;i<a.size();i++)
		res=(res+(LL)fpw(x,a[i].first)*a[i].second)%M;
	return res;
}
#include<ctime>
int main()
{
	freopen("capitalism.in","r",stdin);
	freopen("capitalism.out","w",stdout);
	X.push_back(make_pair(1,1));
	scanf("%d%d%d",&n,&z,f+1);
	for(int i=1;i<n;i++)
		for(int j=i+1;j<=n;j++)
			scanf("%d",&c[i][j]),(f[j]+=c[i][j])%=M;
	Num[1].push_back(make_pair(0,f[1]));
	Den[1].push_back(make_pair(0,1));
	Den[1].push_back(make_pair(1,(M-(1-f[1]))%M));
	for(int i=2;i<=n;i++)
	{
		Den[i].push_back(make_pair(0,1));
		Den[i].push_back(make_pair(1,(M-(1-f[i]))%M));
		for(int j=1;j<i;j++)
			Num[i]=Num[i]+X*Num[j]*c[j][i];
		for(int j=1;j<i;j++)
		{
			Den[j]=Den[j]*Den[i];
			Num[j]=Num[j]*Den[i];
		}
		Den[i]=Den[i-1];
	}
	u=Num[n];
	v=Den[n];
	u1=derivative(u)*v-u*derivative(v);
	v1=v*v;
	u1=u1*X;
	u2=derivative(u1)*v1-u1*derivative(v1);
	v2=v1*v1;
	u2=u2*X;
	int z2=(LL)z*z%M;
	int E1=(LL)calc(u1,z)*inv(calc(v1,z))%M;
	int E2=(LL)calc(u2,z2)*inv(calc(v2,z2))%M;
	int ans=(E2-(LL)E1*E1)%M;
	if(ans<0)ans+=M;
	printf("%d\n",ans);
	//cout<<clock()<<endl;
	return 0;
}

T2:

在這裏插入圖片描述
n20n\le20

題解:

既然實力值高的人獲勝的概率是定值pp,那麼一個人是誰就不重要,他的實力值具體是多少也不重要,重要的是他的排名。這樣就可以把狀態數壓縮,只需要記ft,kf_{t,k}表示2t2^t個人中排名第k+1k+1位的人勝出的概率。
在這裏插入圖片描述
把與k,ik,i無關項提前,其餘項儘量寫成iikik-i形式。
在這裏插入圖片描述
Code:

#include<bits/stdc++.h>
#define maxn (1<<20)+5
using namespace std;
const int mod = 998244353, G = 3;
int n,p,A,B,C,D,E,ans,v[maxn],f[maxn],a[maxn],b[maxn],tmp[maxn],fac[maxn],inv[maxn];
inline int Pow(int a,int b){
	int s=1; for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) s=1ll*s*a%mod;
	return s;
}
int w[maxn],r[maxn],wlen;
void init(const int N){
	fac[0]=inv[0]=1;
	for(int i=1;i<=N;i++) fac[i]=1ll*fac[i-1]*i%mod;
	inv[N]=Pow(fac[N],mod-2);
	for(int i=N-1;i>=1;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
	wlen=N,w[0]=1,w[1]=Pow(G,(mod-1)/wlen);
	for(int i=2;i<=wlen;i++) w[i]=1ll*w[i-1]*w[1]%mod;
}
void NTT(int *a,int len,int flg){
	for(int i=0;i<len;i++) if(i<(r[i]=r[i>>1]>>1|(i&1?len>>1:0))) swap(a[i],a[r[i]]);
	for(int i=2;i<=len;i<<=1)
		for(int j=0,t=wlen/i;j<len;j+=i)
			for(int k=j,o=0;k<j+i/2;k++,o+=t){
				int u=a[k],v=1ll*w[flg==1?o:wlen-o]*a[k+i/2]%mod;
				a[k]=(u+v)%mod,a[k+i/2]=(u-v)%mod;
			}
	if(flg==-1) for(int i=0,Inv=Pow(len,mod-2);i<len;i++) a[i]=1ll*a[i]*Inv%mod;
}
void solve(int m){
	for(int i=0;i<m;i++)//!!!
		a[i]=1ll*f[i]*inv[i]%mod*inv[m-1-i]%mod,
		tmp[i+1]=(tmp[i]+f[i])%mod;
	for(int i=0;i<=m;i++)//!!!
		b[i]=(1ll*tmp[i]*(1-p)+1ll*(tmp[m]-tmp[i])*p)%mod*inv[i]%mod*inv[m-i]%mod;
	NTT(a,m<<1,1),NTT(b,m<<1,1);
	for(int i=0;i<m<<1;i++) f[i]=1ll*a[i]*b[i]%mod;
	NTT(f,m<<1,-1);
	for(int i=0,c=1ll*inv[m+m]*fac[m]%mod*fac[m]%mod;i<m<<1;i++)
		f[i]=2ll*f[i]*fac[i]%mod*fac[m+m-1-i]%mod*c%mod;
}
int main()
{
	freopen("comparison.in","r",stdin);
	freopen("comparison.out","w",stdout);
	scanf("%d%d%d%d%d%d%d",&n,&p,&A,&B,&C,&D,&E);
	for(int i=0;i<1<<n;i++) v[i]=A%E,A=(1ll*A*B+C)%D;
	init(1<<n);
	f[0]=1;
	for(int i=0;i<n;i++) solve(1<<i);
	sort(v,v+(1<<n),greater<int>());
	for(int i=0;i<1<<n;i++) ans=(ans+1ll*v[i]*f[i])%mod;
	printf("%d\n",(ans+mod)%mod);
}

T3:

在這裏插入圖片描述
在這裏插入圖片描述

題解:

O(n2)O(n^2)做法就是同構字符串的KMP,【COCI 2011-2012 contest#4】decode,將每個位置的值改寫爲與前一個相同的值的位置之差,由於KMP比較時需要與區間左端點取max,所以不好擴展。
在這裏插入圖片描述
因爲變化的位置是O()O(字符集大小)的,所以建出關聯數列的後綴數組後比較兩個關聯數列變化後的子串可以做到O()O(字符集大小),於是可以通過sortsort建出關聯後綴的後綴數組並求出其height值,求子串的出現次數時二分兩邊範圍即可。

Code:

#include<bits/stdc++.h>
#define maxn 100005
using namespace std;
char cb[1<<18],*cs,*ct;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<18,stdin),cs==ct)?0:*cs++)
inline void read(int &a){
	char c;while(!isdigit(c=getc()));
	for(a=c-'0';isdigit(c=getc());a=a*10+c-'0');
}
int n,Q,a[maxn],nxt[maxn][10],pos[maxn][12];
char s[maxn];
namespace SA{
	const int Log = 16;
	int ary[4][maxn],b[maxn],lg[maxn]={-1},st[maxn][Log+1];
	int *sa=ary[0],*rk=ary[1],*nsa=ary[2],*nrk=ary[3];
	void build(int n,int m,int *a){
		for(int i=1;i<=n;i++) b[a[i]]++;
		for(int i=1;i<=m;i++) b[i]+=b[i-1];
		for(int i=1;i<=n;i++) sa[b[a[i]]--]=i;
		for(int i=1;i<=n;i++) rk[sa[i]]=rk[sa[i-1]]+(a[sa[i-1]]!=a[sa[i]]);
		for(int k=1;rk[sa[n]]<n;k<<=1){
			for(int i=1;i<=n;i++) b[rk[sa[i]]]=i;
			for(int i=n;i>=1;i--) if(sa[i]-k>0) nsa[b[rk[sa[i]-k]]--]=sa[i]-k;
			for(int i=n-k+1;i<=n;i++) nsa[b[rk[i]]--]=i;
			for(int i=1;i<=n;i++) nrk[nsa[i]]=nrk[nsa[i-1]]+(rk[nsa[i-1]]!=rk[nsa[i]]||rk[nsa[i-1]+k]!=rk[nsa[i]+k]);
			swap(sa,nsa),swap(rk,nrk);
		}
		for(int i=1,j,k=0;i<=n;st[rk[i]][0]=k,i++)
			for(k&&(k--),j=sa[rk[i]-1];a[i+k]==a[j+k];k++);
		for(int i=1;i<=n;i++) lg[i]=lg[i>>1]+1;
		for(int j=1;j<=Log;j++)
			for(int i=1;i+(1<<j)-1<=n;i++)
				st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
	}
	inline int LCP(int x,int y){
		if(x==y) return n-x+1;
		if((x=rk[x])>(y=rk[y])) swap(x,y); x++;
		int k=lg[y-x+1];
		return min(st[x][k],st[y-(1<<k)+1][k]);
	}
}
namespace SA2{
	const int Log = 16;
	int sa[maxn],rk[maxn],lg[maxn]={-1},st[maxn][Log+1];
	typedef pair<bool,int> pii;
	pii solve(int x,int y){
		int i=1,*p=pos[x],*q=pos[y];
		for(int lim=min(*p,*q);i<=lim;i++){
			if(p[i]!=q[i]) return pii(p[i]<q[i],min(p[i],q[i]));
			int len=p[i]+SA::LCP(x+p[i]+1,y+q[i]+1)+1;
			if(len<min(p[i+1],q[i+1])) return pii(a[x+len]<a[y+len],len);
		}
		return pii(p[i]==q[i]?i>*p:p[i]<q[i],min(p[i],q[i]));
	}
	bool cmp(int i,int j){return solve(i,j).first;}
	void build(){
		for(int i=1;i<=n;i++) sa[i]=i;
		sort(sa+1,sa+1+n,cmp);
		for(int i=1;i<=n;i++) rk[sa[i]]=i,i>1&&(st[i][0]=solve(sa[i],sa[i-1]).second);
		/*for(int i=1;i<=n;i++){
			for(int j=1;j<=*pos[sa[i]];j++){
				printf("0 ");
				for(int k=pos[sa[i]][j]+1;k<pos[sa[i]][j+1];k++) printf("%d ",a[sa[i]+k]);
			}
			putchar('\n');
		}*/
		for(int i=1;i<=n;i++) lg[i]=lg[i>>1]+1;
		for(int j=1;j<=Log;j++)
			for(int i=1;i+(1<<j)-1<=n;i++)
				st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
	}
	inline int LCP(int x,int y){
		if(x==y) return n-x+1;
		if((x=rk[x])>(y=rk[y])) swap(x,y); x++;
		int k=lg[y-x+1];
		return min(st[x][k],st[y-(1<<k)+1][k]);
	}
	void work(int x,int y){
		int L,R,l,r,mid;
		for(l=1,r=rk[x];l<r;) mid=(l+r)>>1,LCP(sa[mid],x)>=y-x+1?(r=mid):(l=mid+1);
		L=l;
		for(l=rk[x],r=n;l<r;) mid=(l+r+1)>>1,LCP(sa[mid],x)>=y-x+1?(l=mid):(r=mid-1);
		R=l;
		printf("%d\n",R-L+1);
	}
}
int main()
{
	freopen("conscience.in","r",stdin);
	freopen("conscience.out","w",stdout);
	scanf("%d%d%s",&n,&Q,s+1);
	for(int i=n,c;i>=1;i--){
		memcpy(nxt[i],nxt[i+1],10<<2);
		c=s[i]-'0',a[nxt[i][c]]=nxt[i][c]-i,nxt[i][c]=i;
		for(int j=0;j<=9;j++) if(nxt[i][j]) pos[i][++*pos[i]]=nxt[i][j]-i;
		sort(pos[i]+1,pos[i]+1+*pos[i]),pos[i][*pos[i]+1]=n+1-i;
	}
	a[n+1]=a[0]=-1,SA::build(n,n,a);
	SA2::build();
	int l,r;
	while(Q--) read(l),read(r),SA2::work(l,r);
}
發佈了379 篇原創文章 · 獲贊 139 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章