传送门:牡牛和牝牛
思路:这道题目使用DP的做法,先将原问题变成求一个满足1和1之间有k个0的字符串的问题,设定一个f[i]数组表示所有长度为i的并且以1结尾的字符串的数量。
当第i位放1之后,上一个1可以放的位置就是1~i-k-1这些位置,而长度为i的字符串满足要求的字符串的数量又等于所有长度为i-k-1的以第i-k-1位结尾为1的字符串的数量的总和,
也就是f[1]+f[2]+...f[i-k-1]=f[i]。前面的一部分可以用前缀和数组的方式求得,而最终的答案就是s[n],s[n]的含义是所有长度在1~n之间符合要求的字符串的数目。
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=1e5+10,mod=5e6+11;
int f[N];
int s[N];
int main()
{
int n,k;
scanf("%d%d",&n,&k);
f[0]=1;
s[0]=1;
for(int i=1;i<=n;i++)
{
f[i]=s[max(i-k-1,0)];
s[i]=(s[i-1]+f[i])%mod;
}
cout<<s[n]<<endl;
return 0;
}
——————————————————分割线——————————————————————
思路:对于题目里的x^x%1000,可以直接用快速幂实现。
而剩下的问题就是求解a1+a2+a3+...+ak==n的解的数量的问题,对于这里可以利用一种在组合计数里面经常用到的方法,隔板法, 上面的式子可以转化成在下面n个小球的n-1个间隙之中选择k-1个间隙放隔板的问题,放完隔板之后就会有k个部分,每一个部分小球的数目就是ai的值。解的数目就是C(n-1,k-1)。
但又因为题目里面没有说将答案对某个数字取模,所以最后的答案要用高精度来算。
这里因为n,k的范围都比较小,所以可以采用杨辉三角的公式递推求值,
C(n,m)=C(n-1,m)+C(n-1,m-1)
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=150;
int f[1000][100][N];
int k,x;
int qmi(int a,int k,int p)
{
int res=1;
while(k)
{
if(k&1)res=(ll)res*a%p;
a=(ll)a*a%p;
k>>=1;
}
return res;
}
void add(int c[],int a[],int b[])
{
for(int i=0,t=0;i<N;i++)
{
t+=a[i]+b[i];
c[i]=t%10;
t/=10;
}
}
int main()
{
scanf("%d%d",&k,&x);
int n=qmi(x%1000,x,1000);
for(int i=0;i<n;i++)
for(int j=0;j<=i&&j<k;j++)
if(!j) f[i][j][0]=1;
else
add(f[i][j],f[i-1][j-1],f[i-1][j]);
int *g=f[n-1][k-1];
int i= N-1;
while(!g[i]) i--;
while(i>=0) cout<<g[i--];
return 0;
}