atcoderAGC021 E - Ball Eat Chameleons(组合数学)

传送门:https://agc021.contest.atcoder.jp/tasks/agc021_e

大致题意:
吃球的变色龙
• 笼子里有 N N N只变色龙。
• 变色龙在没吃东西的时候是蓝色的。它根据以下规则变色:
• 一只蓝色的变色龙在吃过的红球比蓝球多时变成红色。
• 一只红色的变色龙在吃过的蓝球比红球多时变成蓝色。
• 一开始,所有变色龙都没吃东西。你可以执行以下操作 K K K次来喂它们:
• 选择一个红球或蓝球。
• 扔进笼子。然后,其中一只变色龙吃掉球。
• 扔 K K K次球后,所有变色龙都是红色的。求你有多少种可能的扔 K K K个球的方案。 对 998244353 998244353 998244353取模。两种方案不同当且仅当存在 i i i使得第 i i i次操作扔的球颜色不 同。
• 1 < = N , K < = 5 ∗ 1 0 5 • 1<=N, K<=5*10^5 1<=N,K<=5105


首先可以发现一个显然的结论:
一个变色龙最后为红色只有两种可能:
①吃的红球比蓝球多
②相同且最后一个为蓝球
显然 R < B R<B R<B时肯定不合法

我们讨论 R = B R=B R=B的时候
可以转化到图上,任意一种丢法对应着 ( 0 , 0 ) (0,0) (0,0) ( R , B ) (R,B) (R,B)的一条路线
显然最后一个球必须是蓝球
• 终点为蓝球
画到图上
• 路线不能与直线 y − x > = B − N − 1 y-x>=B-N-1 yx>=BN1相交
这也很好理解。我们可以发现前面迫不得已多出来的变色龙后面的红球无法弥补

可以推导到 R > B R>B R>B的时候结论类似,不过不要求终点为蓝球

#include
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define P pair
#define Pil pair
#define Pli pair
#define Pll pair
#define pb push_back 
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
#define ls ch[x][0]
#define rs ch[x][1]
int rd()
{
    int sum = 0;char c = getchar();bool flag = true;
    while(c < '0' || c > '9') {if(c == '-') flag = false;c = getchar();}
    while(c >= '0' && c <= '9') sum = sum * 10 + c - 48,c = getchar();
    if(flag) return sum;
    else return -sum;
}
const int p = 998244353;
int n,k;
int fac[1001000];
int inv[1001000];
int max(int a,int b){return a>b?a:b;}
int del(int a,int b){return ((a-b)%p+p)%p;}
int calc(int a,int b){return (a+b)%p;}
int Pow(int a,int x)
{
	int now = 1;
	for(;x;x >>= 1,a = 1ll*a*a%p) if(x&1)now = 1ll*now*a%p;
	return now;
}
int C(int i,int j)
{
	if(j > i || j < 0) return 0;
	int now = 1ll*fac[i]*inv[j]%p;
	now = 1ll*now*inv[i-j]%p;
	return now;
}
int main()
{
	n = rd();k = rd();
    int ans = 0;
    fac[0] = 1;inv[0] = 1;rep(i,1,1000000) fac[i] = 1ll*fac[i-1]*i%p,inv[i] = Pow(fac[i],p-2);
	rep(x,max((k+1)/2,n),k)
    {//(x,n-x)
    	int y = (x*2==k?k-x-1:k-x),t = x-n+1;
    	ans = calc(ans,del(C(x+y,x),C(x+y,y-t)));
	}
	printf("%d\n",ans);
    return 0;
}

你可能感兴趣的:(atcoder,组合数学)