• AtCoder Grand Contest 038


    ABC 略

    D. Unique Path

    E. Gachapon

    考虑 \(P(ans\leqslant n)=n![x^n]\prod(e^{A_ix}-\sum\limits_{j=0}^{B_i-1}\frac{(\frac {A_i}S)^jx^j}{j!})\),后面的内容也就顺理成章了。

    我们的欲求式是 \(\sum\limits_{n=0} P(ans>n)=\sum\limits_{n=0} 1-P(ans\leqslant n)=\sum\limits_{n=0} 1-n![x^n]F(x)=-\sum\limits_{n=0} n![x^n](F(x)-e^x)\)

    套路地,我们 \(dp\) 出它的系数,即 \(F(x)=\sum\limits_{i,j} dp_{i,j}e^{\frac iS}x^j\),则 \(\sum\limits_{n=0} n![x^n]F(x)=\sum\limits_{n=0} \sum\limits_{i,j} dp_{i,j}\dfrac{(\frac iS)^{n-j}n!}{(n-j)!}=\sum\limits_{i,j} dp_{i,j}j!\sum\limits_{n=0} \dbinom{n}{j} (\frac iS)^{n-j}\)

    事实上 \(\sum\limits_{n=0}\dbinom{n}{a}b^{n-a}=(\frac 1{1-b})^{a+1}\),于是做完了。

    #include<bits/stdc++.h>
    using namespace std;
    #define inf 1e9
    const int maxn=2e5+10;
    const int mod=998244353;
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }
    const int N=405;
    int n,m,A[N],B[N],S,dp[N][N],F[N][N],tmp[N],ta,tb,ans;
    int fac[N],inv[N],ifc[N];
    inline int ksm(int x,int y){
    	int res=1;
    	while(y){
    		if(y&1)res=1ll*res*x%mod;
    		x=1ll*x*x%mod;y>>=1;
    	}return res;
    }
    int main(){
    	n=read();
    	for(int i=1;i<=n;i++)
    		A[i]=read(),B[i]=read(),S+=A[i];
    	fac[0]=inv[1]=ifc[0]=1;
    	for(int i=2;i<N;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
    	for(int i=1;i<N;i++)fac[i]=1ll*fac[i-1]*i%mod;
    	for(int i=1;i<N;i++)ifc[i]=1ll*ifc[i-1]*inv[i]%mod;
    	dp[0][0]=1;tmp[0]=mod-1;
    	for(int i=1;i<=n;i++){
    		int w=1ll*A[i]*inv[S]%mod;
    		for(int j=1;j<B[i];j++)tmp[j]=1ll*tmp[j-1]*w%mod*inv[j]%mod;
    		for(int a=ta;a>=0;a--)
    			for(int j=tb;j>=0;j--)
    				for(int k=0;k<B[i];k++)
    					F[a][j+k]=(F[a][j+k]+1ll*dp[a][j]*tmp[k])%mod;
    		ta+=A[i],tb+=B[i]-1;
    		for(int a=ta;a>=A[i];a--)
    			for(int j=tb;j>=0;j--)
    				F[a][j]=(dp[a-A[i]][j]+F[a][j])%mod;
    		for(int a=0;a<=ta;a++)
    			for(int b=0;b<=tb;b++)
    				dp[a][b]=F[a][b],F[a][b]=0;
    	}
    	for(int i=0;i<ta;i++){
    		int K=1ll*i*inv[S]%mod,kk=ksm(1-K+mod,mod-2);
    		for(int j=0;j<=tb;j++)
    			ans=(ans+1ll*dp[i][j]*fac[j]%mod*ksm(kk,j+1))%mod;
    	}printf("%d\n",mod-ans);
        return 0;
    }
    

    F. Two Permutations

    易知一个置换环要么保留,要么全部还原。我们考虑 P 的置换环 \(a\) 和 Q 的置换环 \(b\) 的共同元素 \(i\)

    • \(P_i=Q_i=i\),则无论 \(a,b\) 选或不选,都是 \(1\) 的贡献

    • \(P_i=i,Q_i\neq i\),若 \(b\) 不选,则有 \(1\) 的贡献

    • \(P_i\neq i,Q_i=i\),若 \(a\) 不选,则有 \(1\) 的贡献

    • \(P_i=Q_i\neq i\),若 \(a,b\) 同时选或不选,都有 \(1\) 的贡献

    • \(P_i\neq i,Q_i\neq i,P_i\neq Q_i\),若 \(a,b\) 都不选,则有 \(1\) 的贡献

    套路网络流即可。

    #include<bits/stdc++.h>
    using namespace std;
    #define inf 1e9
    #define ll long long
    const int maxn=1e6+10;
    const int mod=1e9+7;
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }
    int n,m,P[maxn],Q[maxn],idp[maxn],idq[maxn],cnt,ans,S,T;
    int dep[maxn];queue<int>q;
    int beg[maxn],nex[maxn],to[maxn],w[maxn],e=1;
    #define pii pair<int,int>
    #define mkp make_pair
    map<pair<int,int>,int>mp;
    inline void add(int x,int y,int z){
    	if(mp[mkp(x,y)]){w[mp[mkp(x,y)]]+=z;return;}
    	++e;nex[e]=beg[x];beg[x]=e;to[e]=y;w[e]=z;mp[mkp(x,y)]=e;
    	++e;nex[e]=beg[y];beg[y]=e;to[e]=x;w[e]=0;
    }
    inline int bfs(){
    	for(int i=1;i<=T;i++)dep[i]=0;
    	dep[S]=1;q.push(S);
    	while(!q.empty()){
    		int x=q.front();q.pop();
    		for(int i=beg[x];i;i=nex[i]){
    			int t=to[i];
    			if(w[i]&&!dep[t]){
    				dep[t]=dep[x]+1;
    				q.push(t);
    			}
    		}
    	}return dep[T];
    }
    inline int dfs(int x,int lim){
    	if(x==T||!lim)return lim;
    	int res=0;
    	for(int i=beg[x];i&&lim;i=nex[i]){
    		int t=to[i];
    		if(w[i]&&dep[t]==dep[x]+1){
    			int f=dfs(t,min(lim,w[i]));
    			if(!f){dep[t]=0;continue;}
    			w[i]-=f;w[i^1]+=f;
    			res+=f;lim-=f;
    		}
    	}return res;
    }
    int main(){
    	n=read();
    	for(int i=1;i<=n;i++)P[i]=read()+1;
    	for(int i=1;i<=n;i++)Q[i]=read()+1;
    	for(int i=1,x;i<=n;i++)if(!idp[i]){++cnt;x=i;while(!idp[x])idp[x]=cnt,x=P[x];}
    	for(int i=1,x;i<=n;i++)if(!idq[i]){++cnt;x=i;while(!idq[x])idq[x]=cnt,x=Q[x];}
    	S=++cnt,T=++cnt;
    	for(int i=1;i<=n;i++){
    		if(P[i]==i&&Q[i]==i){ans++;continue;}
    		if(P[i]==Q[i]){add(idp[i],idq[i],1),add(idq[i],idp[i],1);continue;}
    		if(P[i]==i){add(S,idq[i],1);continue;}
    		if(Q[i]==i){add(idp[i],T,1);continue;}
    		add(idp[i],idq[i],1);
    	}
    	while(bfs())ans+=dfs(S,inf);
    	printf("%d\n",n-ans);
    	return 0;
    }
    
  • 相关阅读:
    PHP环境搭建-修改密码
    先挖个坑....
    usaco 1.2.1(指针技巧)
    warfare(最大生成树裸题)
    最大生成树(最小生成树同理)
    快排
    简单邻接表代码实现
    并查集模板题
    并查集
    get 新技能
  • 原文地址:https://www.cnblogs.com/syzf2222/p/16122939.html
Copyright © 2020-2023  润新知