CodeForces - 1312D - Count the Arrays【组合数学】

题意:

  • m m 个数中选出 n 1 n-1 个数,构造出一个有一个峰值,峰值左严格递增,峰值右严格递减的数列。

思路

  • m m 个数中选出 n 1 n-1 个数: C ( m , n 1 ) C(m, n-1)
  • 最大的数作为峰值,毫无疑问
  • 从剩下的 n 2 n-2 个数中选择一个作为峰值左右相同的数: n 2 n-2
  • 现在还剩 n 3 n-3 个数,怎么处理嘞?这 n 3 n-3 个数每个都有两种选择:(1)选择作为峰值的左膀(2)选择作为峰值的右臂. 所以总共有 2 n 3 2^{n-3} 种组合
  • 所以最后答案: a n s = C ( m , n 1 ) ( n 2 ) 2 n 3 ans=C(m, n-1)*(n-2)*2^{n-3}

注意

  • 当然 n = 2 n=2 时,不可能找到合法数列,所以此时答案是0~

My Code

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
inline int read()
{
    int x = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9') { if(c == '-') f = -f; c = getchar(); }
    while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
    return x * f;
}

const int maxN = 30;
const int maxBit = 70;
const int p = 998244353;

ll qpow(ll x, ll y)
{
    ll base = x, ans = 1;
    while(y)
    {
        if(y & 1)
            ans *= base, ans %= p;
        base *= base, base %= p;
        y >>= 1;
    }
    return ans % p;
}

ll C(ll n, ll m)
{
    if(n < m) return 0;
    if(n == 0) return 1;
    m = min(m, n - m);
    ll up = 1, down = 1;
    for(int i = 0; i < m; ++ i )
    {
        up *= (n - i), up %= p;
        down *= (i + 1), down %= p;
    }
    ll down_inverse = qpow(down, p - 2);
    return up * down_inverse % p;
}

int n, m;

int main()
{
    while(~scanf("%d%d", &n, &m))
    {
        if(m < n - 1 || n == 2)
        {
            puts("0");
            continue;
        }
        ll ans = (C(m, n - 1) * (n - 2) % p) * (qpow(2, n - 3) % p) % p;
        cout << ans << endl;
    }
    return 0;
}
发布了273 篇原创文章 · 获赞 76 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_44049850/article/details/104767859