Loading

[Offer收割]编程练习赛3 - 题目3 : 智力竞赛

智力竞赛 

Problem's Link

 ----------------------------------------------------------------------------

Mean: 

略(中文题).

analyse:

比赛中最先想到的是三维dp,但思考后发现可以压缩为二维,状态转移方程:

  • dp[i][j]=min(dp[i][j],dp[i][j-(right+fault)]+right)

其中dp[i][j]表示:

  • 到通过第i关为止,在总共只有j次答题机会的情况下,总共至少需要答对dp[i][j]次

最终answer为dp[n][m].

Time complexity: O(N*M*M)

 

view code

/**
* -----------------------------------------------------------------
* Copyright (c) 2016 crazyacking.All rights reserved.
* -----------------------------------------------------------------
*       Author: crazyacking
*       Date  : 2016-03-30-21.00
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long(LL);
typedef unsigned long long(ULL);
const double eps(1e-8);

const int N=1010;
LL a[N],dp[N][N];

int main()
{
   int Cas;
   cin>>Cas;
   while(Cas--)
   {
       int n,m,s,t;
       cin>>n>>m>>s>>t;
       for(int i=1;i<=n;++i)
       {
           cin>>a[i];
           fill(dp[i],dp[i]+N,INT_MAX);
       }
       fill(dp[0],dp[0]+N,0);
       for(int i=1;i<=n;++i)
       {
           int max_right=a[i]/s;
           if(a[i]%s) ++max_right;
           for(int right=0;right<=max_right;++right)
           {
               int dif=a[i]-s*right,fault=0;
               if(dif>0)
               {
                   if(dif%t) fault=dif/t+1;
                   else fault=dif/t;
               }
               fault=max(fault,0);
               for(int chance=m;chance>=right+fault;--chance)
                   dp[i][chance]=min(dp[i][chance],dp[i-1][chance-(right+fault)]+right);
           }
       }
       if(dp[n][m]<INT_MAX)
           cout<<dp[n][m]<<endl;
       else
           cout<<"No"<<endl;
   }
   return 0;
}
/*

*/


/**< 带注释版 */
/**
* -----------------------------------------------------------------
* Copyright (c) 2016 crazyacking.All rights reserved.
* -----------------------------------------------------------------
*       Author: crazyacking
*       Date  : 2016-03-30-21.00
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long(LL);
typedef unsigned long long(ULL);
const double eps(1e-8);

const int N=1010;
LL a[N],dp[N][N];

int main()
{
   int Cas;
   cin>>Cas;
   while(Cas--)
   {
       int n,m,s,t;
       cin>>n>>m>>s>>t;
       for(int i=1;i<=n;++i)
       {
           cin>>a[i];
           fill(dp[i],dp[i]+N,INT_MAX);
       }
       fill(dp[0],dp[0]+N,0);
       for(int i=1;i<=n;++i) // 到第i关为止
       {
           //对于本关,答对max_right题时,不算错题的分值也能通关
           int max_right=a[i]/s;
           if(a[i]%s) ++max_right;
           for(int right=0;right<=max_right;++right)  // 枚举答对的题数
           {
               //答对right题时,需要答错多少题
               int dif=a[i]-s*right,fault=0;
               if(dif>0)
               {
                   if(dif%t) fault=dif/t+1;
                   else fault=dif/t;
               }
               fault=max(fault,0);
               for(int chance=m;chance>=right+fault;--chance)
                   dp[i][chance]=min(dp[i][chance],dp[i-1][chance-(right+fault)]+right);
               // dp[i][j] ------到本关为止,若只有chance次答题机会,本关答对了right题,若本关能够通关,到本关为止总共最少需要答对多少题
               // chance-(right+fault) ----- 总共答题机会为chance,本关用了right+fault次,前面所有关只有chance-(right+fault)次机会
           }
       }
       if(dp[n][m]<INT_MAX)
           cout<<dp[n][m]<<endl;
       else
           cout<<"No"<<endl;
   }
   return 0;
}
/*

*/

 

posted @ 2016-03-30 23:19  北岛知寒  阅读(484)  评论(0编辑  收藏  举报