CF1188E Problem from Red Panda

cf

我们可以把题目中的选择\(k-1\)种颜色,并且全部改成剩下那种颜色改为选择一种颜色的球增加\(k\)个,然后所有颜色的球减少\(1\)

然后考虑一个状态\(b\)能否在第\(x\)轮到达.对于每一位\(i\),需要在之前操作中选择\(\frac{b_i-(a_i-x)}{k}\)次才可以到达(注意这里的次数要是整数,否则不合法).再根据题目的一些条件,可以发现经过\(x\)轮能到达\(b\)状态当且仅当

  • \(\forall i,k|(b_i-(a_i-x))\)\(\sum_{i=1}^{k}\frac{b_i-(a_i-x)}{k}=x\)
  • 过程中所有的\(a_i\)要为非负整数

条件2可以推出对于一个\(a_i\),必须在前\(a_i+1\)轮内对\(i\)加一次\(k\).同理,要在前\(a_i+k+1\)轮内对\(i\)加两次\(k\),要在前\(a_i+2k+1\)轮内对\(i\)加三次\(k\)...依此类推

由于每轮只能给一个颜色\(i\)\(k\),所以随着轮数的增加,我们必须要用一些轮去给某些\(i\)\(k\)来保持非负,如果对于\(x\)轮可以操作到,且在\(x+1\)轮时,前\(x+1\)的轮都不够做完前面所有颜色\(i\)所必要的加\(k\)次数了,那么也就意味着\(x\)轮为最多能操作的轮数,并且可以发现如果\(x\)是有限的,那么一定满足\(x<k\),因为给一个数加\(k\)后,至少后\(k\)轮都不必要再加\(k\),也就是在满足操作轮数尽可能多的情况下一个数在\(k\)轮内只会被加一次,如果出现不满足的情况,那么一定没有一个\(i\)加了超过\(1\)\(k\)

然后考虑轮数有限的情况下的方案.枚举总共操作轮数\(x\),我们可以发现不管给某个颜色\(i\)加多少次\(k\),这个当前的\(a_i'\)和初始\(a_i\)一定满足\(a_i-a_i'\equiv x\pmod {k}\),也就是轮数有限的情况下每种操作轮数后得到的状态一定两两不同.那么设\(x\)轮要执行\(c_x\)次必要的加\(k\)操作,剩下操作的可以任意分配给每个\(i\),可以发现这里操作不用考虑顺序,且操作出的状态只和给每种颜色分配的次数有关且一一对应,方案数就可以写成\(\binom{x-c_x+k-1}{k-1}\)

还有可能可以操作无限次.我们可以由前面的一些性质推导出\(x\bmod k\)不同的\(x\)得到的状态不会算重.反之,\(x\bmod k\)相同的状态是会算重的,不过可以发现\(x\)更小的状态一定会在\(x\)更大的状态算重,因为这个操作是无限轮的,那么你用这两个\(x\)之间相差的\(pk\)轮分别给每个颜色加\(p\)次从而得到一样的状态.所以对于每个\(j\in[0,k)\),我们只要在一个尽量大的\(x\)(满足\(k|(x-j)\))处给答案加上\(\binom{x-c_x+k-1}{k-1}\)即可,大概在\(1e6\)及更大的数左右取(因为再往后走\(x-c_x\)会是一个定值,即不会有其他的新状态)

#include<bits/stdc++.h>
#define LL long long
#define uLL unsigned long long

using namespace std;
const int N=2e6+10,mod=998244353;
int rd()
{
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
    return x*w;
}
void ad(int &x,int y){x+=y,x-=x>=mod?mod:0;}
int fpow(int a,int b){int an=1;while(b){if(b&1) an=1ll*an*a%mod;a=1ll*a*a%mod,b>>=1;}return an;}
int ginv(int a){return fpow(a,mod-2);}
int n,m,mx,a[N],c[N],b[N],fac[N],iac[N];
int C(int a,int b){return b<0||a<b?0:1ll*fac[a]*iac[b]%mod*iac[a-b]%mod;}

int main()
{
    fac[0]=1;
    for(int i=1;i<=N-5;++i) fac[i]=1ll*fac[i-1]*i%mod;
    iac[N-5]=ginv(fac[N-5]);
    for(int i=N-5;i;--i) iac[i-1]=1ll*iac[i]*i%mod;
    n=rd();
    for(int i=1;i<=n;++i)
    {
      	a[i]=rd();
    	mx=max(mx,a[i]),++c[a[i]];
    }
    for(int i=1,s=0;i<=n;++i)
    {
    	s+=c[i-1];
    	if(s>i) break;
    	++m;
    }
    int ans=0;
    if(m<n)
    {
    	for(int i=0,s=0;i<=m;++i)
    	{
    	    ad(ans,C(i-s+n-1,n-1));
    	    s+=c[i];
    	}
    }
    else
    {
    	int s=0;
    	for(int i=1;i<=n;++i)
    	{
    	    s+=max((mx-1-a[i]+n)/n,0);
    	    if(a[i]!=mx) ++b[a[i]%n];
    	}
    	for(int i=n,j=mx;i;--i,--j)
    	{
    	    ad(ans,C(j-s+n-1,n-1));
    	    s-=b[(j+n-1)%n],b[(j+n-1)%n]-=j?c[j-1]:0;
    	}
    }
    printf("%d\n",ans);
    return 0;
}
posted @ 2020-03-08 21:59  ✡smy✡  阅读(272)  评论(0编辑  收藏  举报