[AGC002F]Leftmost Ball

Posted StaroForgin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[AGC002F]Leftmost Ball相关的知识,希望对你有一定的参考价值。

Leftmost Ball

题解

首先一个序列白化后合法必须要求前缀白球数不小于前缀颜色数,否则肯定有个白球染的不是该种颜色的第一个球。
所以显然我们可以将球分成白球与有颜色的球往里放,有颜色的球重要的是第一个放置(未被染白的)的位置,这个位置会影响前缀颜色数,确定了第一个位置,其它球在后面乱填就好了,而每一个白球的位置都很重要,都会影响前缀和。

所以我们可以想到依次确定当前的第一个空位填那个球,记 d p i , j dp_i,j dpi,j表示已经填了 i i i个白球, j j j组有颜色球的方案数,显然转移就是下一个填白球还是有颜色的球,有转移方程式,
d p i , j = d p i − 1 , j + ( n k − i − ( j − 1 ) ( k − 1 ) − 1 k − 2 ) d p i , j − 1 ​ dp_i,j=dp_i-1,j+\\binomnk-i-(j-1)(k-1)-1k-2dp_i,j-1​ dpi,j=dpi1,j+(k2nki(j1)(k1)1)dpi,j1白球显然是不需要区分颜色的,而后面有颜色的球可以先不考虑颜色,只要保证填的数量比白球少,将在后面的序列放置的方案数,也就是那个组合数乘上转移就行。最后再乘上 n ! n! n!表示有颜色的球第一个出现的颜色序列就行,毕竟不同颜色间是等价的。

顺着 d p dp dp一次就可以了。
时间复杂度 O ( n k ) O\\left(nk\\right) O(nk)

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 2005
#define MAXM 4000005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL; 
typedef long double ld;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f;
const int mo=1e9+7;
const int mod=1e5+3;
const int inv2=5e8+4;
const int jzm=2333;
const int zero=2000;
const int n1=1000;
const int M=100000;
const int orG=3,ivG=332748118;
const long double Pi=acos(-1.0);
const double eps=1e-12;
template<typename _T>
_T Fabs(_T x)return x<0?-x:x;
template<typename _T>
void read(_T &x)
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0')if(s=='-')f=-1;s=getchar();
	while('0'<=s&&s<='9')x=(x<<3)+(x<<1)+(s^48);s=getchar();
	x*=f;

template<typename _T>
void print(_T x)if(x<0)x=(~x)+1;putchar('-');if(x>9)print(x/10);putchar(x%10+'0');
int gcd(int a,int b)return !b?a:gcd(b,a%b);
int add(int x,int y,int p)return x+y<p?x+y:x+y-p;
void Add(int &x,int y,int p)x=add(x,y,p);
int qkpow(int a,int s,int p)int t=1;while(s)if(s&1)t=1ll*t*a%p;a=1ll*a*a%p;s>>=1;return t;
int n,K,dp[MAXN][MAXN],fac[MAXM],inv[MAXM],ff[MAXM];
void init()
	fac[0]=fac[1]=inv[0]=inv[1]=ff[1]=1;
	for(int i=2;i<=n*K;i++)
		fac[i]=1ll*i*fac[i-1]%mo,
		ff[i]=1ll*(mo-mo/i)*ff[mo%i]%mo,
		inv[i]=1ll*ff[i]*inv[i-1]%mo;

int C(int x,int y)
	if(x<0||y<0||x<y)return 0;
	return 1ll*fac[x]*inv[y]%mo*inv[x-y]%mo;

signed main()
	read(n);read(K);init();dp[0][0]=1;
	if(K==1)puts("1");return 0;
	for(int i=1;i<=n;i++)
		for(int j=0;j<=i;j++)
			if(j<i)Add(dp[i][j],dp[i-1][j],mo);
			if(j>0)Add(dp[i][j],1ll*C(n*K-i-(j-1)*(K-1)-1,K-2)*dp[i][j-1]%mo,mo);
		
	printf("%lld\\n",1ll*fac[n]*dp[n][n]%mo);
	return 0;


谢谢!!!

以上是关于[AGC002F]Leftmost Ball的主要内容,如果未能解决你的问题,请参考以下文章

AGC002F Leftmost Ball

AtCoder Grand Contest 002 (AGC002) F - Leftmost Ball 动态规划 排列组合

Leftmost Ball

agc002fLeftmost Ball

ATcoder 2000 Leftmost Ball

AT2000 Leftmost Ball