题意
给定
和
,求
。
。
时间限制:2秒。
解题思路
如果只看到了自变量由大到小,是很难想到怎么做的。
拿出笔来画一画,其实自变量增大的途径有2条,一是加1,一是乘以K。
答案就是
加到
的方案数。
也就是
能够拆分成
的方案数。
那么是不是和之前的一题很像啊?
另外一题的链接
这题的解题报告
这题的设法也是挺类似的,但是要注意一点。
显然
。
可以发现
。所以转移的时候要借助一个辅助数组。
设
表示
可以拆分成的最大的数为
的方案数。
则
表示
可以拆分成最大的数为
的方案数。
则
则 。
在计算答案的时候,设 表示做到 进制下的第 位,并且拆分的最大值为 的方案数。
转移跟 的转移类似。
高精度卡常?
我AC了之后,看了某些大神的代码,发现了一些可以优化的地方。(当然优化之后还是不够他跑得快)
①在赋值的时候不需要将整个数组赋值,只需要更新位数和对应位数的值。
②高精度乘法:
“%”运算常数大,所以要减少”%”运算的次数。
开一个
的
数组,每次
,然后最后扫的时候再进位。
心得
①
要转化为
进制,才能够看清楚问题的本质。
②顺着推不行考虑倒着来。
③有一个小trick,就是
中
,这个时候心态不要崩了,因为解决问题的大方向总是对的,这个时候可以考虑什么辅助的转移。
④高精度常数可能太大,这样会吃亏的。
代码
#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;
}