一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情。
题目描述
这是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;
}