题解:P13234 [GCJ 2015 Finals] Campinatorics

· · 题解

简要分析

枚举 3 的个数,若个数为 k

选出这 k3 的方案数即为选出 kk 列再乘以在这 kk 列中选出 k 个位置的方案数,为:

\binom{n}{k}^2 k!

剩下 n-kn-k 列,先安排 n-k2,方案数 (n-k)!

最后考虑 1,如果填 2 可以看作一个序列 a_1,a_2,\dots a_{n-k} 表示每一行的 2 放在哪一列,就可以看作错排问题,要求 1 的位置和 2 的位置不重合。

那么总方案数就是:

\sum_{k=x}^{n}\binom{n}{k}^2 k!(n-k)!d(n-k) 其中错排的递推方程式是 $d(x)=(x-1)(d(x-1)+d(x-2))$,其中 $d(0)=1,d(1)=0$。 ## 代码 ```cpp #include<bits/stdc++.h> using namespace std; const int mod = 1e9+7; int t,n,x,jie[1000005],inv[1000005],d[1000005]; int qpow(int x,int y){ int ans=1; while(y){ if(y&1)ans=1ll*ans*x%mod; y>>=1; x=1ll*x*x%mod; } return ans; } long long C(int x,int y){ if(y>x)return 0; if(y==0||y==x)return 1; return 1ll*jie[x]*inv[x-y]%mod*inv[y]%mod; } int solve(int x){ if(x==0)return 1; if(x==1)return 0; long long ans=jie[x]; for(int i=1;i<=x;i++){ ans+=1ll*C(x,i)*jie[x-i]%mod*(i&1?-1:1)+mod; ans%=mod; } // cout<<x<<" "<<ans<<'\n'; return ans; } int main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin>>t; jie[0]=1; d[0]=1,d[1]=0; for(int i=1;i<=1e6;i++){ jie[i]=1ll*jie[i-1]*i%mod; inv[i]=qpow(jie[i],mod-2); if(i>=2)d[i]=(1ll*(i-1)*(d[i-1]+d[i-2]))%mod; } for(int _=1;_<=t;_++){ cin>>n>>x; int ans=0; for(int i=x;i<=n;i++){ ans+=1ll*C(n,i)*C(n,i)%mod*jie[i]%mod*jie[n-i]%mod*d[n-i]%mod; ans%=mod; } printf("Case #%d: %d\n",_,ans); } return 0; } ```