原题链接:https://ac.nowcoder.com/acm/contest/74362/F
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
小红定义一个字符串的“连续段”数量为:相同字符的极长连续子串的数量。例如,"aabbaaa"共有 3 个连续段:"aa"+"bb"+"aaa"。
现在,小红希望你求出,长度为x+y,包含恰好有x个'a'和y个'b'组成的字符串,连续段数量恰好为i的字符串数量。你需要回答i∈[1,x+y]的每个i的答案。
两个正整数x,y,用空格隔开。 1≤x,y≤1000
输出共x+y行,第i行代表连续段数量为i的字符串数量。由于答案可能过大,请对1e9+7取模。
2 1
0 2 1
两个'a'和一个'b'组成的字符串有 3 个,其中 2 个的连续段数量为 2:"aab"和"baa",其中一个的连续段数量为 3:"aba"
假设有k段,那么必然是以下俩种情况之一
(1)a,b,a,b,a,b,a,....
a有odd=(k+1)/2段,b有even=k/2段,
也就是在a的x-1个空隙中的odd-1个空隙中插入板子隔开,所以有C(x-1,odd-1)
在b的y-1个空隙中的even-1个空隙中插入板子隔开,所以有C(y-1,even-1)。
综合知有C(x-1,odd-1)*C(y-1,even-1)中情况
(2)b,a,b,a,b,a,b,.....
b有odd=(k+1)/2段,a有even=k/2段,
也就是在b的y-1个空隙中的odd-1个空隙中插入板子隔开,所以有C(y-1,odd-1)
在a的x-1个空隙中的even-1个空隙中插入板子隔开,所以有C(x-1,even-1)。
综合知有C(y-1,odd-1)*C(x-1,even-1)中情况
综合上述俩种情况连续段数量为k的字符串数量为C(x-1,odd-1)*C(y-1,even-1)+C(y-1,odd-1)*C(x-1,even-1)
所以我们只需要预处理组合数,然后枚举每一个k即可。
时间复杂度:预处理阶乘O(1000),枚举时间大概为O((x+y)*log(1000)),最终时间复杂度大概为O(1000+(x+y)*log(1000))。
空间复杂度:只使用了存储阶乘的数组,空间复杂度为O(1000)。
cpp代码如下:
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int N=1010,mod=1e9+7;
LL fact[N];
LL qmi(LL x,int k) //快速幂求逆元
{
LL res=1;
while(k){
if(k&1)res=res*x%mod;
x=x*x%mod;
k>>=1;
}
return res;
}
LL inv(int x) //求逆元
{
return qmi(x,mod-2);
}
LL C(int n,int m) //求组合数C(n,m)
{
if(m<0 || n-m<0)return 0; //遇到负数要提前返回0
return fact[n]*inv(fact[m])%mod*inv(fact[n-m])%mod;
}
int main()
{
//预处理阶乘
fact[0]=1;
for(int i=1;i<=1000;i++)fact[i]=fact[i-1]*i%mod;
int x,y;
cin>>x>>y;
for(int i=1;i<=x+y;i++) //枚举每一个i,输出答案
{
int odd=(i+1)/2,even=i/2;
cout<<(C(x-1,odd-1)*C(y-1,even-1)%mod+C(y-1,odd-1)*C(x-1,even-1)%mod)%mod<<'\n';
}
return 0;
}