zoukankan      html  css  js  c++  java
  • 【组合数学】AGC036C

    找性质的能力不行

    Problem Statement

    We have a sequence of $N$ integers: $x=(x_0,x_1,cdots,x_{N−1})$. Initially, $x_i=0$ for each $i (0≤i≤N−1)$.

    Snuke will perform the following operation exactly $M$ times:

    Choose two distinct indices $i,j (0≤i,j≤N−1, i≠j)$. Then, replace $x_i$ with $x_i+2$ and $x_j$ with $x_j+1$.
    Find the number of different sequences that can result after $M$ operations. Since it can be enormous, compute the count modulo $998244353$.

    Constraints

    • $2≤N≤10^6$
    • $1≤M≤5×10^5$
    • All values in input are integers.

    题目分析

    这类题的一般套路是把一些奇奇怪怪的操作转化成局部量守恒;或者是操作对一些特殊量的影响有什么限制。

    这里首先能够看出限制一:$forall a_i le 2m$.

    再来考察一下操作有什么特性:在两个位置$i,j$分别加上$2,1$也就是把$j$的奇偶性翻转;$i$的奇偶性不影响。初始每个位置都为偶。这说明全部操作只有$m$次翻转奇偶性的机会,由此得到限制二:$sumlimits [x_i为奇数]le m$.

    这两个限制的必要性上面已经论述了,充分性可以通过对$m$归纳得到。

    现在问题变成了:

    给定$n,m$,求长度为$n$的可空数列${x_i}$满足$[sum x_i=3m ]and [forall x_i le 2m ]and [sumlimits [x_i为奇数]le m]$的个数。

    第一条限制很好处理,问题主要是第二条限制。

    首先来考虑单纯满足第二条限制的数列个数,不妨记$f(n,m,k)$表示把$m$分为$n$组非空、且奇数个数$le k$的方案数。那么这里有$f(n,3m,m)=sumlimits _{p=1,p≡3mpmod 2}^n {frac{3m-p}{2}+n-1choose n-1}{n choose p}$,其中$p$是枚举的奇数个数。

    容斥地考虑,现在要计算的另一部分问题应是$[exists x_i > 2m ]and [sumlimits [x_i为奇数]le m]$,也即:枚举最大数位置$pos$,把$m$分为$n$组非空、奇数个数$le k$、且$x_{pos}$非空的方案数。

    这里的“某一位置非空”就是很经典的问题了,可以先用$m-1$构造非空数列、再将$1$加到$x_{pos}$上;也可以再容斥一次,用$m$构造$n$的方案减去用$m$构造$n-1$的方案,意即此位置为零不占用$m$.

     1 #include<bits/stdc++.h>
     2 #define MO 998244353
     3 typedef long long ll;
     4 const int maxn = 3000000;
     5 
     6 ll n,m,ans;
     7 ll inv[maxn],fac[maxn];
     8 
     9 ll C(ll n, ll m)
    10 {
    11     if (n < m) return 0;
    12     return fac[n]*inv[m]%MO*inv[n-m]%MO;
    13 }
    14 ll f(ll n, ll m, ll k)
    15 {
    16     ll ret = 0;
    17     for (ll p=0; p<=k; p++)
    18         if (((m-p)&1)==0){
    19             ret = (ret+C((m-p)/2ll+n-1, n-1)*C(n, p)%MO)%MO;
    20         }
    21     return ret;
    22 }
    23 int main()
    24 {27     scanf("%lld%lld",&n,&m);
    28     fac[0] = inv[0] = inv[1] = 1;
    29     for (int i=2; i<=n+3*m; i++)
    30         inv[i] = (MO-1ll*MO/i*inv[MO%i]%MO);
    31     for (int i=1; i<=n+3*m; i++)
    32         inv[i] = inv[i-1]*inv[i]%MO, fac[i] = fac[i-1]*i%MO;
    33 //    ans = (f(n, 3*m, m)-n*(f(n, m, m)-f(n-1, m, m))%MO+MO)%MO;
    34     ans = (f(n, 3*m, m)-n*(f(n, m-1, m))%MO+MO)%MO;
    35     printf("%lld
    ",ans);
    36     return 0;
    37 }

    END

  • 相关阅读:
    7年Java后端被淘汰,一路北漂辛酸史。。。
    vue jqury如何获取元素中的属性
    02-Elenment 引入使用
    01
    vuex 全局store,前后端交互
    五分钟搞懂Vuex
    VueX 的使用
    vue解决前后端跨域问题
    rest_framework/api.html
    Vue中使用markdown
  • 原文地址:https://www.cnblogs.com/antiquality/p/11788351.html
Copyright © 2011-2022 走看看