题目:http://acm.hdu.edu.cn/showproblem.php?pid=4658
题目大意:给你两个个数n,k,要求你算出把n拆分,且每个数的个数都不超过k的种数。
思路:五边形定理。。 具体可以看看我转的那篇文章,写得挺详细的。。再贴一个在别人博客看到的一个关键的东西:
对于(1-x^k)*(1-x^2k)*...*(1-x^nk),可令x^k=y;再利用五边形定理将其打开;
两个式子相除那里是直接用等比数列数和就可以得出来,这里想了半天,问学长才知道的。。= =
先贴个代码,代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef __int64 lld;
const int MOD = 1e9 + 7 ;
const int MAXN = 100001;
lld get_q(lld x)
{
lld ans = (lld)3*x*x-x;
return ans/2;
}
lld Q[MAXN],P[MAXN];
void init()
{
Q[0] = 0;
for(int i = 1;i<MAXN;i++)
{
if(i&1) Q[i] = get_q(i/2+1);
else Q[i] = get_q(i/2*(-1));
}
P[0] = P[1] =1;
for(int i = 2;i<MAXN;i++)
{
for(int j = 1;;j++)
{
if(Q[j]>i) break;
int t = j;
if(t&1) t = t/2 + 1;
else t = t/2;
if(t&1) P[i] = P[i] + P[i - Q[j]];
else P[i] = P[i] - P[i - Q[j]];
if(P[i]>MOD) P[i] = P[i]%MOD;
if(P[i]<0) P[i] = P[i]+MOD;
//P[i] = (P[i]%MOD+MOD)%MOD; 这样写超时。。
}
}
}
lld solve(int n,int k)
{
lld ans = 0;
for(int i = 0;;i++)
{
if(Q[i]*k>n) break;
int t = i;
if(t&1) t = t/2 + 1;
else t = t/2;
if(t&1) ans = ans - P[n - Q[i]*k];
else ans = ans + P[n - Q[i]*k];
if(ans>MOD) ans = ans%MOD;
if(ans<0) ans = ans+MOD;
//ans = (ans%MOD+MOD)%MOD; 这样写超时。。
}
return ans;
}
int main()
{
init();
int T;
scanf("%d",&T);
while(T--)
{
int n,k;
scanf("%d%d",&n,&k);
printf("%I64d\n",solve(n,k));
}
return 0;
}