【atcoder】GP 2 [agc036C]

  题目传送门:https://atcoder.jp/contests/agc036/tasks/agc036_c

  题目大意:给你一个长度为$N$初始全0的序列,每次操作你可以找两个不同的元素,一个自增1,一个自增2,问$M$次操作后,能出现多少种不同的序列。

  这道题比赛时分析的时候漏条件了,导致最后一个样例一直过不去,不过考虑上漏掉的条件分析起来也是比较复杂的。

  我们可以发现如果一个序列$a$是合法的,当且仅当它满足以下条件:

    1. $\sum_{i=1}^{N} a_i=3M$。

    2. 整个序列里至多有$M$个奇数。

    3. $\max_{i=1}^{N} a_i<=2M$。

  证明可以考虑对$M$数学归纳。

  我们可以先忽略条件3,枚举奇数的个数$i$,那么就是相当于对于一个全是偶数的数列,选择$i$个加上1,总方案数为$\sum_{i=1}^{\min(N,M)}\binom{N}{i}\binom{N-1+3M-i}{N-1}$,可以在$O(n+m)$的时间复杂度下计算。

  然后在考虑减去不满足条件3的方案数。由于序列中大于$2M$的元素最多只有一个,因此我们可以钦定那个大于$2M$的元素为$a_1$,并将其减去$2M$,这样操作后的序列,并且原序列如果满足原序列是满足条件1,2,不满足条件3,当且仅当操作后的序列满足以下条件:

    a. $\sum_{i=1}^{N} a_i=3M$。

    b. 整个序列至多有$M$个奇数。(减去$2M$不改变奇偶性)

    c. $a_1>0$。

  我们再把这些方案看作两部分相减:忽略条件c的方案减去考虑条件c非法的答案,而我们发现这样的忽略条件c的方案条件与上面的条件1,2相似,可以用相似方法统计,而考虑条件c时因为钦定$a_1=0$,所以直接序列整体平移,$N$自减1再统计即可。

  代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#define ll long long
#define mod 998244353
#define Mod1(x) (x>=mod?x-mod:x)
#define Mod2(x) (x<0?x+mod:x)
#define maxn 3000010
inline ll read()
{
    ll x=0; char c=getchar(),f=1;
    for(;c<'0'||'9'<c;c=getchar())if(c=='-')f=-1;
    for(;'0'<=c&&c<='9';c=getchar())x=x*10+c-'0';
    return x*f;
}
inline void write(ll x)
{
    static int buf[20],len; len=0;
    if(x<0)x=-x,putchar('-');
    for(;x;x/=10)buf[len++]=x%10;
    if(!len)putchar('0');
    else while(len)putchar(buf[--len]+'0');
}
inline void writeln(ll x){write(x); putchar('\n');}
inline void writesp(ll x){write(x); putchar(' ');}
ll fac[maxn],inv[maxn];
int n,m;
inline ll power(ll a,ll b)
{
    ll ans=1;
    for(;b;b>>=1,a=a*a%mod)
        if(b&1)ans=ans*a%mod;
    return ans;
}
inline ll C(int n,int m){return fac[n]*inv[m]%mod*inv[n-m]%mod;}
inline ll calc(int n,int m,int k)
{
    ll sum=0;
    for(int i=0;i<=n&&i<=k;i++)
        if(!((m-i)&1)&&m>=i)sum=(sum+C(n,i)*C((m-i)/2+n-1,n-1))%mod;
    // writeln(sum);
    return sum;
}
int main()
{
    n=read(); m=read();
    fac[0]=inv[0]=1;
    for(int i=1;i<=n+3*m;i++){
        fac[i]=fac[i-1]*i%mod;
        inv[i]=power(fac[i],mod-2);
    }
    ll ans=(calc(n,3*m,m)-n*(calc(n,m,m)-calc(n-1,m,m)+mod))%mod;
    writeln(Mod2(ans));
    return 0;
}
agc036C

 

posted @ 2019-07-22 22:21  QuartZ_Z  阅读(326)  评论(1编辑  收藏