SRM520 DIVI-500pts

題目鏈接如下:

http://community.topcoder.com/stat?c=problem_statement&pm=11496&rd=14545

這個題的狀態很好寫出,假設dp[i][j]表示:到第i個人其得到j分時的情況個數,那麼可以寫出狀態:

dp[i][j]=sum(dp[i-1][p],p>j)*S[i][j],其中S[i][j]表示第i個人得到j分的方法數。不難看出sum(dp[i-1][p],p>j)可以在計算的過程中預處理得出,如果S[i][j]也可以預處理的話,那麼狀態轉移的時間複雜度可以優化到O(nm),n爲人數,m爲最大分值,可行!

現在我們來處理S[][],對於只做出一題和兩題的情況,其方法數很好算,對於做出三題的情況,我是先計算將j得分分配給後面兩題有多少中情況,然後加上最前面一題,其實方法有些挫的,還有更好的方法,我做的時候沒有想到。一開始想的時候,很容易聯想到將n個相同的球分給3個不同盒子的問題,初中問題啊,用插板法(一開始還忘記了。。。),其實解這個題的思路並不是插板法,但是就當溫習啦。

PS:一開始實現的時候是用二維數組的,然後Test的時候就會有Kill信號,最後都改爲一維數組了。另外,發現自己的代碼能力越來越差,寫的時候很多小Bug,然後有cha不出來。

代碼如下:

#define MOD (1000000007)
#define MAXN 200000
#define _min(a,b) ((a)<(b)?(a):(b))
#define _max(a,b) ((a)>(b)?(a):(b))

int pnum[22];
int toppoint[22];

long long S[MAXN+5];
long long dp[22][MAXN+5];
long long pre[MAXN+5];
long long Stemp[MAXN];
long long psum[MAXN];

void calcS2(int ind,vector<int>& points,int a,int b){
     int i;
     for(i=2;i<=toppoint[ind];i++){
         int P=i;
         P--;
         if(P>points[a]){
            S[i]=_min(points[a],points[b]-P+points[a]);
         }
         else{
            S[i]=P;
         }
     }
}

void calcS3(int ind,vector<int>& points){
     int i,P;
     for(i=3;i<=toppoint[ind];i++){
         int l=_max(2,i-points[0]);
         int r=_min(i-1,points[1]+points[2]);
         S[i]=(Stemp[r]-Stemp[l-1]+MOD)%MOD;
     }
}

void calcS(vector<int>& points,vector<string>& des,int i){
      int j;
       memset(S,0,sizeof(S));
       if(pnum[i]==0) S[0]=1;
       else if(pnum[i]==1){
          for(j=1;j<=toppoint[i];j++)
             S[j]=1;
       }
       else if(pnum[i]==2){
            if(des[i][0]=='Y'&&des[i][1]=='Y'){
               calcS2(i,points,0,1);
            }
            else if(des[i][0]=='Y'&&des[i][2]=='Y'){
               calcS2(i,points,0,2);
            }
            else{
               calcS2(i,points,1,2);
            }
       }
       else{
            calcS3(i,points);
       }
}


class SRMIntermissionPhase
{
public:
	int countWays(vector <int> points, vector <string> description)
	{
		int n=description.size();
		int i,j,P;
		int sum=0;
		for(i=0;i<n;i++){
            pnum[i]=0;
            sum=0;
            for(j=0;j<3;j++)
              if(description[i][j]=='Y'){pnum[i]++;sum+=points[j];}
            toppoint[i]=sum;
        }
        memset(S,0,sizeof(S));
        memset(Stemp,0,sizeof(Stemp));
        
        //calc S[][]
        for(i=2;i<=points[1]+points[2];i++){
           P=i;
           P--;
           if(P>points[1]){
               Stemp[i]=_min(points[1],points[2]-P+points[1]);
           }
           else{
               Stemp[i]=P;
           }
        }
        for(i=3;i<=points[1]+points[2];i++)
           Stemp[i]=(Stemp[i-1]+Stemp[i])%MOD;
                 
        //calc dp[][]
        memset(dp,0,sizeof(dp));
        memset(pre,0,sizeof(pre));
         calcS(points,description,0);
        for(j=toppoint[0];j>=pnum[0];j--){
          
           dp[0][j]=S[j];
        }
        for(i=1;i<n;i++){
           
           calcS(points,description,i);
           
           pre[MAXN+1]=0;
           for(j=MAXN;j>=0;j--)
              pre[j]=(pre[j+1]+dp[i-1][j])%MOD;
              
           for(j=toppoint[i];j>=pnum[i];j--){
              dp[i][j]=(pre[j+1]*S[j])%MOD;
           }
        }
        long long res=0;
        for(j=toppoint[n-1];j>=pnum[n-1];j--)
           res=(res+dp[n-1][j])%MOD;
        return (int)res;
	}
};


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章