HDU 6651 Final Exam(思维)

http://acm.hdu.edu.cn/showproblem.php?pid=6651

题意

期末考试有n个问题,总分为m分,每个问题的分数在0到m之间,假如一个问题的分数为x,那么你需要复习至少x+1个小时才能做出这个题。

问不管试卷结构怎样你都能做出至少k个题所要复习的最少时间。

题解

对每个问题都复习m+1个小时即总复习k*(m+1)个小时必能做出k个题;

这样保证合法但并不一定最优;

什么情况合法且最优?

考虑到试卷结构变化对复习策略有影响,那么让试卷结构对你最不利的时候求出来的答案合法,其他情况肯定也合法了。

想象一下:有个坏老师很狡猾,出题时尽量让你花的复习时间少的题目做不出来,这样就可以让你做不出来的题目更多。

所以我们不妨让复习每个问题的时间相等。

怎么确定这个时间?

考虑到复习的时间越长能做出来的题目越多,即这个事情是单调的.

那么我们可以二分这个时间t.

举个例子:

n=6,m=117,k=4;

我们二分到最后是t=40,即复习每个问题得时间分别为40,40,40,40,40,40;

那么我们可以求得答案为40*6=240;

如果你以为这就做完了那你可以wa了。。

因为其实还可以更优:

39 39 40 40 40 40

所以我们最后应该再算一下最多还可以让多少个t变成t-1且答案仍然合法。

计算这个我们也可以采用二分。这个例子答案应该为238。

代码很好写:

 1 #define bug(x) cout<<#x<<" is "<<x<<endl
 2 #include <bits/stdc++.h>
 3 using namespace  std;
 4 #define ll long long
 5 int T;
 6 ll n,m,k;
 7 int check(ll x){
 8     ll g=m/x;
 9     if(n-g>=k)return 1;
10     return 0;
11 }
12 int main(){
13     scanf("%d",&T);
14     while(T--){
15         scanf("%lld%lld%lld",&n,&m,&k);
16         ll l=1,r=1e9+5,ans=(m+1)*k;
17         ll res=1e9+5;
18         while(l<r){
19             ll m1=(l+r)/2;
20             if(check(m1)){
21                 res=min(res,m1);
22                 r=m1;
23             }
24             else l=m1+1;
25         }
26         ll l1=0,r1=n-k+1,x=0;
27         while(l1<r1){
28             ll m1=(l1+r1)/2;
29             ll h=m-m1*(res-1);
30             ll g=h/res;
31             if(m1+g<=n-k){
32                 x=m1;
33                 l1=m1+1;
34             } 
35             else r1=m1;
36         }
37         res*=n;
38         res-=x;
39         ans=min(ans,res);
40         printf("%lld\n",ans);
41     }   
42 }
43 /*
44 100
45 6 117 4
46 4 1 2
47 */

 

posted @ 2019-08-12 21:03  Venux  阅读(354)  评论(0编辑  收藏  举报