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