k-size字符串(牛客小白月赛25 组合数学)

k-size字符串

链接:https://ac.nowcoder.com/acm/contest/5600/B
题解:https://ac.nowcoder.com/discuss/428377

题目描述
牛妹最近在研究k-size字符串。
一个字符串为k-size指,字符串的连续段共有 k k 个。所谓连续段指尽可能多的相同连续字母组成的子串。
例如:aabbbccc为3-size,因为(‘aa’ ‘bb’ ‘ccc’),ababaab为6-size,因为 (‘a’ ‘b’ ‘a’ ‘b’ ‘aa’ ‘b’)。
牛妹想知道,由 n n 个 ‘a’ 字符, m m 个 ‘b’ 字符,组成长度为 n + m n+m 的k-size字符串,共有多少种组成方式?由于该数可能过大,请对 1 e 9 + 7 1e9+7 取模。
输入描述:
三个正整数 n , m n,m k k ,用空格隔开。
输出描述:
一个正整数,为方案数对 1 e 9 + 7 1e9+7 取模的结果。
示例1
输入
2 2 2
输出
2
示例2
输入
1 2 3
输出
1

思路:
只有两种不同的元素 a 'a' b 'b' 来组成 k k 段,那么最后的结果肯定是 a b a b a b a b abab\cdots abab 不同的段交叉。

k k 是偶数时,先拿出 k / 2 k/2 a a k / 2 k/2 b b 摆好: a b a b a b a b abab\cdots abab ,然后剩下的 a a b b 就是往已经摆好的位置上插。

这是高中排列组合中的一个问题:有 x x 个相同元素分成 y y 组,每组有非负整数个元素。
解法 x x 个元素和劈 y 1 y-1 刀,共 x + y 1 x+y-1 个位置,在这些位置上选 x x 个位置放上元素,那么剩余位置就相当于是劈了 y 1 y-1 刀,分成了 y y 组,每组都是大于等于零个,方案数即 C x + y 1 x C_{x+y-1}^{x} 。k是偶数时就是 ( n k / 2 ) (n-k/2) 个元素分成 k / 2 k/2 组。

k k 是奇数时,与上面类似,先拿出 k / 2 + 1 k/2+1 a a k / 2 k/2 b b 摆好: a b a a b a aba\cdots aba ,然后剩下的往里插。

Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
ll power(ll a, ll b)
{
    ll res = 1;
    while (b)
    {
        if (b & 1)
            res = res * a % mod;
        b >>= 1, a = a * a % mod;
    }
    return res % mod;
}
ll inv(ll x) { return power(x, mod - 2); }
ll C(ll n, ll m)
{
    ll res = 1;
    for (int i = 1; i <= m; i++)
        res = res * (n - i + 1) % mod * inv(i) % mod;
    return res;
}
ll f(ll x, ll y) //x个相同元素分成y个非负整数的组的方案数
{
    if (x < 0 || y <= 0)
        return 0;
    return C(x + y - 1, x);
}
int main()
{
    ll n, m, k;
    cin >> n >> m >> k;
    ll ans = 0;
    if (k & 1)
        ans = (f(n - k / 2, k / 2) * f(m - k / 2 - 1, k / 2 + 1) + f(n - k / 2 - 1, k / 2 + 1) * f(m - k / 2, k / 2)) % mod;
    else
        ans = 2LL * f(n - k / 2, k / 2) * f(m - k / 2, k / 2) % mod;
    cout << ans << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44169557/article/details/106220184
今日推荐