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;
}