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);
}
}
}
}