【牛客網】【java】wyh的考覈

oj地址:wyh的考覈
貼下題,好讓搜索引擎蒐集。

問題描述

wyh非常喜歡lol遊戲,一天,他聽說學校要選拔lol隊員,他非常高興的就去了,選拔規則是,一共有N個評委,每個評委根據線上對線能力和打團能力給出一個[0,M]之間的一個整數作爲分數,然後取平均值,wyh學長非常好奇,他想知道有多少種這樣的情況:

平均分等於其中某一位評委給的分數

例如2個評委,給打的分數都是1分,那麼此時平均分是1分,即等於第一個評委的分數,又等於第二個評委的分數,這樣答案是2

但是由於每個評委打的分都是在[0,M]之間,所以會有很多種情況。

現在請你幫助你們wyh學長數一下有多少種這樣的情況,由於結果會很大,請你對1000000007取餘

解析

dp定義
dp[i][j]表示i個人,j分的情況下,有多少種情況符合題意。
res定位
則答案res爲dp[n-1][i*(n-1)],(i的範圍是0~m),相加再乘以n即可。
進一步解釋res,對於任意一個dp[n-1][i*(n-1)],表示有n-1個人,平均分爲i是,有多少種情況符合題意,此時再增加一個人,只要這個人的分給成i,則就可以複用dp[n-1][i*(n-1)]的值,又根據排列組合可知,要乘以n(因爲n-1的意義不是代表前n-1個人,而是任意選擇n-1個人,也就是c(n,n-1)=n)。
狀態轉移推導:
對於dp[i][j],只需要枚舉當前人能給出的分數即可(0~m),當前人給分爲k時,可以得到dp[i-1][j-k]。挨個相加即可。
dp順序:
dp[i][j]依賴於dp[i-1][j-k],可知,順序爲從上到下,從左到右。第一行爲base case.
填寫base case:
迴歸到題意,只有dp[0][0]是等於1的,其餘情況都不存在,都爲0。
初步代碼如下:

import java.util.*;
public class Main {
    static int mod=1000000007;
    static long[][] dp;
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        while (sc.hasNext()){
            int T=sc.nextInt();
            while(T-->0){
                dp=new long[61][12005];
                int n=sc.nextInt();
                int m=sc.nextInt();
                dp[0][0]=1;
                for(int i=1;i<=n;i++){
                    for(int j=0;j<=i*m;j++){
                        for(int k=0;k<=Math.min(j,m);k++){
                            dp[i][j]+=dp[i-1][j-k];
                            dp[i][j]=dp[i][j]%mod;
                        }
                    }
                }
                long res=0;
                for(int i=0;i<=m;i++){
                    res=(res+dp[n-1][i*(n-1)])%mod;
                }
                System.out.println(res*n%mod);
            }
        }
    }
}

此時雖然答案完全正確了,但是還是AC不了的,需要優化一下,也就是用輔助數據優化前n項和,定義sum[i][j]的意義爲,dp表上第i行的前j項和是多少。然後發現,dp[i]永遠只依賴dp[i-1],所以不需要sum[i][j],優化成一維的sum[i],複用就行。
優化代碼如下(可以AC):

import java.util.*;
public class Main {
    static int mod=1000000007;
    static long[][] dp;
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        while (sc.hasNext()){
            int T=sc.nextInt();
            while(T-->0){
                dp=new long[61][12005];
                long[] sum=new long[12005];
                Arrays.fill(sum,1);
                int n=sc.nextInt();
                int m=sc.nextInt();
                dp[0][0]=1;
                for(int i=1;i<=n;i++){
                    for(int j=0;j<=i*m;j++){
                        if(j>m){
                            dp[i][j]+=(sum[j]-sum[j-m-1]+mod)%mod;
                        }else{
                            dp[i][j]+=sum[j];
                        }
                        dp[i][j]=dp[i][j]%mod;
                    }
                    sum[0]=dp[i][0];
                    //下次循環要用,所以要小於(i+1)*m
                    for(int j=1;j<=(i+1)*m;j++){
                        sum[j]=(dp[i][j]+sum[j-1])%mod;
                    }
                }
                long res=0;
                for(int i=0;i<=m;i++){
                    res=(res+dp[n-1][i*(n-1)])%mod;
                }
                System.out.println(res*n%mod);
            }
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章