标签:Ball 颜色 int ll AGC002F ans Leftmost inv MOD
题目
题目链接:https://atcoder.jp/contests/agc002/tasks/agc002_f
给你 \(n\) 种颜色的球,每个球有 \(k\) 个,把这 \(n\times k\) 个球排成一排,把每一种颜色的最左边出现的球涂成白色(初始球不包含白色),求有多少种不同的颜色序列,答案对 \(10^9+7\) 取模。
\(n,k\leq 2000\)。
思路
最后肯定是有 \(n\) 个白球,以及 \(n\) 种颜色的球各 \(k-1\) 个。观察到一个序列合法,当且仅当任意前缀,白球的数量都不小于其他颜色球的颜色数。
设 \(f[i][j]\) 表示放了 \(i\) 个白球,以及 \(j\) 种颜色的球的方案数。注意可以任意放,不一定是放在一个前缀内。
考虑目前从左开始第一个出现的空位放什么:
- 如果放白球,那么从 \(f[i-1][j]\) 转移过来,条件是 \(i>j\)。
- 如果放新的颜色的球,那么从 \(f[i][j-1]\) 转移过来,且这一个空位必须填这个球,这种颜色剩余的 \(k-2\) 个球,就需要在剩余的 \(nk-i-(j-1)(k-1)-1\) 个空位内随意放。
所以转移为
\[f[i][j]=f[i-1][j]+f[i][j-1]\times (n-j+1)\times \binom{nk-i-(j-1)(k-1)-1}{k-2} \]特判一下 \(k=1\) 的情况即可。
时间复杂度 \(O(nk)\)。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2010,MOD=1e9+7;
int n,k;
ll fac[N*N],inv[N*N],f[N][N];
ll fpow(ll x,ll k)
{
ll ans=1;
for (;k;k>>=1,x=x*x%MOD)
if (k&1) ans=ans*x%MOD;
return ans;
}
void init()
{
fac[0]=inv[0]=1;
for (int i=1;i<=n*k;i++) fac[i]=fac[i-1]*i%MOD;
inv[n*k]=fpow(fac[n*k],MOD-2);
for (int i=n*k-1;i>=1;i--) inv[i]=inv[i+1]*(i+1)%MOD;
}
ll C(int n,int m)
{
if (n<m) return 0;
return fac[n]*inv[m]%MOD*inv[n-m]%MOD;
}
int main()
{
scanf("%d%d",&n,&k);
if (k==1) return printf("1"),0;
init();
for (int i=1;i<=n;i++)
{
f[i][0]=1;
for (int j=1;j<=i;j++)
{
f[i][j]=f[i][j-1]*(n-j+1)%MOD*C(n*k-i-(j-1)*(k-1)-1,k-2)%MOD;
if (j<i) f[i][j]=(f[i][j]+f[i-1][j])%MOD;
}
}
cout<<f[n][n];
return 0;
}
标签:Ball,颜色,int,ll,AGC002F,ans,Leftmost,inv,MOD 来源: https://www.cnblogs.com/stoorz/p/15388614.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。