*PS:原来暴力优化优化是可以过的么qwq,ljoj 数据手动测并没有T。。。最后默默的吐槽一句,附上一个金字塔的图是因为怕我们没有见过吗。。。
题目描述 Description
wyw有一个数字n,他要用这个数字写出一个数字金字塔。
wyw用随机数生成器生成了一个小于n且大于1的正整数k。
wyw找来一张白纸,他在白纸的最低端写下了这个数字n。
wyw在n的上面紧挨着写下了一个正整数a1,a1满足不大于n/k,
wyw又在a1上面写下了一个正整数a2,满足a2不大于a1/k,
时间过了t…
wyw在ah-1的上面写下了一个正整数ah,满足ah不大于ah-1/k
wyw已经无法在ah的上方写出不大于ah/k的数字了
这时,wyw就已经写好了一个高度为h(这里应该为h+1)的数字金字塔
wyw可以按照这个规则写出好多符合条件的数字金字塔。
试问:wyw一共能够写出多少种数字金字塔?wyw能写出的所有的数字金字塔中最高的金字塔的高度是多少?
注意:由于答案可能较大,所以对每一组数据请输出答案对p取模后的值。
输入描述 Input Description
输入数据的第一行包含两个正整数T、p,表示有T组测试数据,p的意义如题目所述
后面跟着T组数据,每组数据仅一行,包含了一个正整数n和k,意义如题目所述
输出描述 Output Description
输出数据一共n行,每行两个整数,表示答案对p取模后的值
样例输入 Sample Input
2 2
6 2
20 3
样例说明:以20 3这组数据为例,wyw能写出的所有金字塔如下
样例输出 Sample Output
1 1
1 1
数据范围及提示 Data Size & Hint
Solution 1 暴力
(codevs 上会T3个点,但手动测了测根本就没T 。。。qwq)
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
long long T,k;
long long n=0,p,cnt;
int f[50000010];
int main()
{
scanf("%lld%lld",&T,&p);
while(T--)
{
scanf("%lld%lld",&n,&k);
int z=n/k;
f[0]=0;
for(int i=1;i<=2*k-1;++i) f[i]=1; // 2*k之前都只能放一个,只有一种方案。
for(int i=2*k;i<=z+1;++i) f[i]=0;
for(int i=2*k;i<=z;++i) // 递推
for(int j=i/k;j>=1;--j)
f[i]=(f[i]%p+f[j]%p)%p;
for(int i=1;i<=z;++i) f[0]=(f[0]%p+f[i]%p)%p; //用0存防止爆空间
if(!f[0]) ++f[0]; // 只能放n也是一种方案
printf("%lld ",f[0]%p);
cnt=1;
while(n/k)
{
n/=k;
cnt=(cnt+1)%p;
}
printf("%lld\n",cnt);
}
return 0;
}
Solution 2 DP
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
long long T,P,n,k;
int S[500020];
int main()
{
scanf("%lld%lld",&T,&P);
S[0]=S[1]=1;
while(T--)
{
scanf("%lld%lld",&n,&k);
int N=n/k,ans2=1;
for(int i=2;i<=N;++i)
S[i]=(S[i-1]+S[i/k])%P;
while(n/k)
{
n/=k;
ans2=(ans2+1)%P;
}
printf("%d %lld\n",S[N],ans2);
}
return 0;
}
/*
用数组s[i]表示以不大于i为底的数字所达到的方案数之和。
F[i]表示以某一数字(i)为底的方案数。
而F[i]恰好为s[i/k].
所以方程式为:s[i] = s[i–1] + f[i]; (类似前缀和)
PS:这里直接把f换成了s
*/