代码源:700、01序列2

303 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情logo.png

题目描述

这是4月3日代码源div2的每日一题。

01序列2 - 题目 - Daimayuan Online Judge

又是大家最喜欢的01序列问题了呢

这次的问题非常的简单,c觉得一个01序列中两个1之间至少要有k个0,现在他要构造出一个长度为n的01序列,请问他有多少种不同的构造方法

这个数字可能会非常大,请你对10^9+7取模

输入格式

一行,给出两个整数n,k

输出格式

一个整数,代表不同的构造方法数

数据范围

1≤n≤10^6

0≤k<n

样例输入

4 2

样例输出

6

\

问题解析

首先题目说了,每两个1直接要有k个0,按照样例来说,n=4,k=2的情况有0000,1000,0100,0010,0001和1001。

发现没有,一直在变的其实是1的位置,0的位置不重要,我们只要保证两个1之间有k个0就行,剩下的位置可以随便排列。那我们就从0枚举1的数量i,然后剩下的位置全塞0就行,但0的数量最少要有(i-1)* k。为了方便其实我们可以忽略掉0,即把1都挨着,只要我们默认两个1之间有k个0就行,这样剩下01串的长度就是n-(i-1) * k,我们只要算在这个长度下,1能有多少种不同的排序即可。这就是高中知识了:C(i)(n-(i-1) * k)。至于C用代码怎么算这里便不多做展开了,感兴趣的可以自行百度学习。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n';
typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 1000050, MOD = 1e9 + 7;

ll fact[N], infact[N];

ll qmi(int a, int b)
{
    ll res = 1;
    while (b)
    {
        if (b & 1) res = res * a % MOD;
        a = a * (ll)a % MOD;
        b >>= 1;
    }
    return res;
}

void init()
{
    fact[0] = infact[0] = 1;
    for (int i = 1; i < N; i++)
        fact[i] = fact[i - 1] * i % MOD;

    infact[N - 1] = qmi(fact[N - 1], MOD - 2);
    for (int i = N - 2; i; i--)
        infact[i] = infact[i + 1] * (i + 1) % MOD;
}

int C(int a, int b)
{
    return (fact[a] * infact[b] % MOD * infact[a - b] % MOD) % MOD;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n, k;
    init();
    cin >> n >> k;
    int i = 1;
    ll res = 1;
    while (i <= n - (i - 1) * k)
    {
        res = (res + C(n - (i - 1) * k, i) % MOD) % MOD;
        i++;
    }
    cout << res << endl;
    return 0;
}