810975(组合数学+容斥原理)

本文介绍了如何解决一个关于字符串010101中111连续段长度恰好为kkk的计数问题,通过容斥原理将问题转化为求特定条件下的组合数,提供了C++代码实现。

810975

[Link](Problem - M - Codeforces)

题意

给你一个长度为 n n n 01 01 01串,有 m m m 1 1 1,求最长 1 1 1连续段长度恰好为 k k k的方案数。

题解

先容斥转化为算 ≤ k \le k k的方案数。 我们把两个连续的 0 0 0中间视为一个长度为 0 0 0 1 1 1连续段,问题转化为求一共 n − m + 1 n-m+1 nm+1 1 1 1连续段,每段长度 ≤ k \le k k,长度和为 m m m的方案数,假设为 f ( n , m , k ) f(n,m,k) f(n,m,k),那么我们的答案就是 f ( n , m , k ) − f ( n , m , k − 1 ) f(n,m,k)-f(n,m,k - 1) f(n,m,k)f(n,m,k1)。对于 f f f的求法我们可以容斥枚举有多少个段违反了 ≤ k \le k k这个限制就可。 容斥枚举多少个 1 1 1连续段不满足 ≤ k \le k k即可。

Code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <unordered_map>
#include <cmath> 
#include <stack>
#include <iomanip>
#include <deque> 
#include <sstream>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 998244353;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
#define tpyeinput int
inline char nc() {static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;}
inline void read(tpyeinput &sum) {char ch=nc();sum=0;while(!(ch>='0'&&ch<='9')) ch=nc();while(ch>='0'&&ch<='9') sum=(sum<<3)+(sum<<1)+(ch-48),ch=nc();}
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
    e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
LL fact[N], infact[N];
LL C(LL n, LL m) {
    if (m > n || m < 0) return 0;
    return fact[n] * infact[m] % mod * infact[n - m] % mod;
}
void init() {
    fact[0] = infact[0] = infact[1] = 1;
    for (int i = 1; i < N; i ++ ) fact[i] = fact[i - 1] * i % mod;
    for (int i = 2; i < N; i ++ ) infact[i] = (mod - mod / i) * infact[mod % i] % mod;
    for (int i = 2; i < N; i ++ ) infact[i] = infact[i] * infact[i - 1] % mod;
}
LL f(int n, int m, int k) {
    if (!k) {
        if (!m) return 1;
        else return 0; 
    }
    if (k > m) return 0;
    int p = n - m + 1;
    LL res = 0;
    for (int i = 0; i <= p; i ++ ) {
        int op = i & 1 ? -1 : 1;
        res += op * C(p, i) *  C(m - i * (k + 1) + p - 1, p - 1) % mod;
    }
    res = (res + mod) % mod;
    return res;
}
int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    cin >> n >> m >> k;
    init();
    if (!k || k > m) cout << f(n, m, k) << endl;
    else cout << (f(n, m, k) - f(n, m, k - 1) + mod) % mod << endl;
    return 0;
}
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值