AtCoder AGC036C GP 2(組成・カウント)

トピックリンク

https://atcoder.jp/contests/agc036/tasks/agc036_c

問題の解決策

最後に、被写体のagc036を補うために時間を持っています。
この質問はかなり......私もテストに料理を考え抜かすることは難しいことではありません

最初のタイトルに変換される:配列を生成することができるときに押圧操作対象と場合にのみ、その長さ\(N \)の合計\(3M \) および以下の最大数\(2M \) 奇数数は超えていない\(M \)
必要性は、誘導の妥当性を証明するために、明確で簡単です。

その後、カウント方法を検討:第二の条件が考慮されていない、の定義\(F(N、M、 K)は、\) の長さを表し、\(\ N-)の合計\(m個\)以下の奇数\(K \)番目プログラムの数、列挙された奇数の数\(Iは\)さらに残りのために\(1-Mの\)がある(F(N、M、\ K)= \和^ {K} _ I {\当量のM(\ MOD 2)} {N- \選択{I} \ {MI FRAC} + {N-2}。1- \} 1-N-\選択)
第二の条件、補変換、最大値を考慮して数がより多い\(2M \)番号のすべての残りの部分がより小さいことを意味\(M \) その後、式を書いていないし、その後何の頭脳式をプッシュしていません!最大数の位置固定\(1 \)を最初の数減算する、(2M \)\を、必要とされる(これは、それが奇数の条件に影響を与えないことが偶数である)\(および\の数) M $は、最初の数字はより大きい\(0 \) 以下の合計(M \)\プログラムの奇数番目。その列挙は非常に面倒であるため、奇数の限られた数は、変換を修正するために設定されています!変換((N-1)\ \ ) 数とするための\(M \)そして、奇数以上ない\(M \) A。

最終的な答えは\(F(N、3M、M)-N(F(N、M、M)-f(1-N、M、M))\)

時間複雑\(O(N + M)\)

コード

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<iostream>
#define llong long long
using namespace std;

inline int read()
{
    int x=0; bool f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
    for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^'0');
    if(f) return x;
    return -x;
}

const int N = 2e6;
const int P = 998244353;
llong fact[N+3],finv[N+3];

llong quickpow(llong x,llong y)
{
    llong cur = x,ret = 1ll;
    for(int i=0; y; i++)
    {
        if(y&(1ll<<i)) {y-=(1ll<<i); ret = ret*cur%P;}
        cur = cur*cur%P;
    }
    return ret;
}
llong comb(llong x,llong y) {return x<0||y<0||x<y ? 0ll : fact[x]*finv[y]%P*finv[x-y]%P;}

llong calc(llong n,llong m,llong k)
{
    llong ret = 0ll;
    for(int i=0; i<=k; i++)
    {
        if((m-i)&1) continue;
        llong tmp = comb(n,i)*comb(((m-i)>>1)+n-1,n-1)%P;
        ret = (ret+tmp)%P;
    }
//  printf("calc %lld %lld %lld=%lld\n",n,m,k,ret);
    return ret;
}

int n,m;

int main()
{
    fact[0] = 1ll; for(int i=1; i<=N; i++) fact[i] = fact[i-1]*i%P;
    finv[N] = quickpow(fact[N],P-2); for(int i=N-1; i>=0; i--) finv[i] = finv[i+1]*(i+1)%P;
    scanf("%d%d",&n,&m);
    llong ans = calc(n,3*m,m);
    ans = (ans-n*(calc(n,m,m)-calc(n-1,m,m)+P)%P+P)%P;
    printf("%lld\n",ans);
    return 0;
}

おすすめ

転載: www.cnblogs.com/suncongbo/p/11297768.html