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 ",ans); 41 } 42 } 43 /* 44 100 45 6 117 4 46 4 1 2 47 */