*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
*/