Codeforces 1312D 组合数学

Cnub

 

 

 

 题意:

给你nn和mm,问满足以下条件的数列的个数:

  • 数列长度为nn
  • 数列值域范围为[1,m][1,m]
  • 数列有且仅有一对相等的数
  • 数列是单峰数列(先严格递增后严格递减,严格递增或严格递减)

思路:数列有且仅有一对相等的数,所以每次要从m个数中挑n-1个数,既是组合数Cn-1m。当找到n-1个数的时候,要满足先严格递增后严格递减,严格递增或严格递减,所以最大值要确定在中间,我们只需要确定最大值两边的数即可,因为要存在一对相等的数且满足单峰数列,要选择的这个存在两次的数不能是这个最大值,要从n-2中选择。当选择出来了出现两次的数的时候,把这个数分别放在最大值的两边,接下来只需要计算剩余n-3个数分配在两边所出现的可能性,既是2n-2。

答案即为

 

 

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <string>
#include <map>
#include <iomanip>
#include <algorithm>
#include <queue>
#include <stack>
#include <set>
#include <vector>
//const int maxn = 1e5+5;
#define ll long long
#define inf  0x3f3f3f3f
#define FOR(i,a,b) for( int i = a;i <= b;++i)
#define bug cout<<"--------------"<<endl
 
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
 
using namespace std;
 const ll mod = 998244353 ;
ll pow_(ll a,ll b)
{
    ll res = 1;
    while(b>0)
    {
        if(b & 1) res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}
 
ll Cnub(ll n,ll m)
{
    ll res = 1;
    ll tmp = 1;
    for(int i = 1; i <= n; i++) res = res * i % mod;
    for(int i = 1; i <= m; i++) tmp = tmp * i % mod;
    for(int i = 1; i <= n-m; i++) tmp = tmp * i % mod;
    return res * pow_(tmp, mod-2) % mod;
}
 
int main()
{
    ll n,m,a,b,c;
    cin>>n>>m;
    if(n == 2)
    {
        cout<<0<<endl;
        return 0;
    }
    ll ans = ((Cnub(m,n-1) * (n-2) % mod) % mod * pow_(2,n-3)%mod) % mod;
    cout<<ans<<endl;
}

 

posted @ 2020-05-10 16:23  阿斯水生产线  阅读(263)  评论(0编辑  收藏  举报