有这样一个递推式:
F(N) = 1 (0 <= N <= K - 1)
F(N) = F(N - K) + F(N / K) (N % K == 0)
F(N) = F(N - 1) (N % K != 0)
给出2个数K和N,计算F(N)。
收起
输入
第1行:一个数K(2 <= K <= 10)。 第2行:大数N(1 <= N <= K^50)。
输出
输出F(N)
输入样例
5 12
输出样例
3
题目大意
有这样一个递推式:
F(N) = 1 (0 <= N <= K - 1)
F(N) = F(N - K) + F(N / K) (N % K == 0)
F(N) = F(N - 1) (N % K != 0)
给出2个数K和N,计算F(N)。
2≤K≤10 1≤N≤k50k50
分析
把F(N) = 1 (0 <= N <= K - 1)改成f(0)=1,然后答案一样。
考虑从0转移到N的一个方案,显然它是若干次加一和乘K。
转换一下思路:现在有一个数字集,开始为空。从0转移到N,加1的时候,相当于给集合添加一个1。乘K就相当于数字集里每个数乘K。最终N可以被表示为数字集里所有数的和。很显然每一个数都是K的幂。并且显然一种方案对应了唯一的转移方案。
那么就转换了问题:把N分解成K的幂的和,问有多少种方案。
然后就联想到51nod上的另一道题:整数分解为2的幂
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1048
那么就可以DP了。设f[i][j]表示把KiKi分解为最大数是KjKj的方案数。不过和这道题的区别是,由f[i-1][]得到f[i][]时要合并k块。
DP理解不了请看这里http://blog.csdn.net/worldwide_d/article/details/54091940
要合并K块,就得再套一个DP:设g[j][x]表示把j∗Kij∗Ki分成最大数是KxKx的方案数,然后g[j][x]=∑xx′=0g[j−1][x′]∗f[i−x′−1][x−x′]g[j][x]=∑x′=0xg[j−1][x′]∗f[i−x′−1][x−x′]
最后的f[i][j]=g[K][j]f[i][j]=g[K][j]
合并答案,就是把N转成K进制,然后剩下的和上面一样。
时间复杂度O(Klog3kN)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 52
#define M 155
#define mo 100000000
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
struct note{
int w,a[M];
void operator = (const note b){
int i;
w=b.w;
fo(i,1,w)a[i]=b.a[i];
}
};note f[N][N],g[N][N],h[11][N],ans,n,c;
long long tt[260];
int i,j,k,K,l,ys,x,tot,wz;
int xx;
char s[32];
note operator + (const note &a,const note &b){
c.w=a.w>b.w?a.w:b.w;
memset(c.a,0,sizeof(c.a));
int i;
fo(i,1,c.w){
c.a[i]+=i<=a.w?a.a[i]:0;
c.a[i]+=i<=b.w?b.a[i]:0;
c.a[i+1]+=c.a[i]/mo;
c.a[i]%=mo;
}
if(c.a[c.w+1])c.w++;
return c;
}
note operator * (const note &a,const note &b){
int i,j;
c.w=a.w+b.w-1;
fo(i,0,c.w+1)tt[i]=0;
long long kk;
fo(i,1,a.w)fo(j,1,b.w){
kk=1ll*a.a[i]*b.a[j];
tt[i+j-1]+=kk;
}
fo(i,1,c.w){
c.a[i]=tt[i]%mo;
tt[i+1]+=tt[i]/mo;
c.w=((tt[i]>=mo)&&(i==c.w))?c.w+1:c.w;
}
return c;
}
int main(){
scanf("%d%s",&K,s+1);
l=strlen(s+1);
n.w=l/8+1;
fo(i,1,l){
int j=(l-i)/8;
n.a[j+1]=n.a[j+1]*10+(s[i]-'0');
}
while(!n.a[n.w]&&n.w>1)n.w--;
f[0][0].w=f[0][0].a[1]=1;
fo(i,1,50){
fo(j,0,i-1)g[1][j]=f[i-1][j];
fo(j,2,K){
fo(x,0,i-1){
g[j][x].w=0;
memset(g[j][x].a,0,sizeof(g[j][x].a));
fo(k,0,x)g[j][x]=g[j][x]+g[j-1][k]*f[i-1-k][x-k];
}
}
fo(j,0,i-1)f[i][j]=g[K][j];
f[i][i].w=f[i][i].a[1]=1;
}
memset(g,0,sizeof(g));
g[0][0].w=g[0][0].a[1]=1;
wz=51;
fo(i,0,50){
ys=0;
fd(j,n.w,1){
x=n.a[j];
n.a[j]=(1ll*ys*mo+x)/K;
ys=(1ll*ys*mo+x)%K;
}
while(!n.a[n.w]&&n.w>1)n.w--;
fo(j,0,i)h[0][j]=g[i][j];
fo(j,1,ys)
fo(x,0,i){
h[j][x].w=0;
memset(h[j][x].a,0,sizeof(h[j][x].a));
fo(k,0,x)h[j][x]=h[j][x]+h[j-1][k]*f[i-k][x-k];
}
fo(j,0,i)g[i+1][j]=h[ys][j];
if(n.w==1&&n.a[1]==0){
n.w=0;
wz=i+1;
break;
}
}
fo(i,0,50)ans=ans+g[wz][i];
printf("%d",ans.a[ans.w]);
fd(i,ans.w-1,1){
xx=log(ans.a[i])/log(10)+1;
fo(j,1,8-xx)putchar('0');
printf("%d",ans.a[i]);
}
return 0;
}