codevs 5251 WYW的數字金字塔

*PS:原來暴力優化優化是可以過的麼qwq,ljoj 數據手動測並沒有T。。。最後默默的吐槽一句,附上一個金字塔的圖是因爲怕我們沒有見過嗎。。。

go to the problem

題目描述 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
*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章