题目链接:http://codeforces.com/gym/101755/problem/K
题目理解: 一家公司想让n个人给他们的产品评论,所以依次去找这n个人,第i个人会评论当且仅当已经有ai个人评论或他确实对这个产品感兴趣,但是这n个人都不对这个产品感兴趣,问这个公司至少要说服几个人对该
产品该兴趣才能至少收到m个人的评论。假如你要强迫人肯定要强迫最前边的,因为说服一个人对评论数贡献为1,而提早做贡献可以带来更多的贡献(因为是一个一个地找人,前面的贡献对后面有用)
对于这种情况,有种强大的方法:二分(二分要强迫的人数)
二分的好处就是简化复杂度,用假设的已知代替未知,对于求一个最多或最少的问题,通常可以用二分来简单地解决
像这题,用二分得到确切的强迫次数,那么就可以直接从前往后遍历了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* */ 2 # include <iostream> 3 # include <stdio.h> 4 # include <string.h> 5 # include <algorithm> 6 # include <cctype> 7 # include <ctime> 8 # include <functional> 9 # include <cmath> 10 # include <bitset> 11 # include <deque> 12 # include <queue> 13 # include <stack> 14 # include <vector> 15 # include <set> 16 # include <map> 17 # include <climits> 18 using namespace std; 19 20 typedef long long LL; 21 const int maxn=2e5+10; 22 int a[maxn]; 23 int n, m; 24 25 bool check(int k) 26 { 27 int ans=0;///记录评论数 28 int i; 29 for(i=0; i<n; i++ ) 30 { 31 if( a[i]<=ans ) 32 ans++; 33 else if( k ) 34 { 35 ans++;///有强迫名额的话优先强迫 36 k--; 37 } 38 if( ans==m ) 39 return true; 40 } 41 return false; 42 } 43 44 int main() 45 { 46 cin>>n>>m; 47 int i; 48 for(i=0; i<n; i++ ) 49 { 50 scanf("%d", &a[i]); 51 } 52 53 int l=0; 54 int r=m; 55 int ans; 56 57 while( l<=r ) 58 { 59 int mid=(l+r)>>1; 60 if( check(mid) )///如果强迫mid个人可以满足条件,就二分减少强迫的人数 61 { 62 r = mid - 1; 63 ans = mid; 64 } 65 else 66 { 67 l = mid+1; 68 } 69 } 70 printf("%d ", min(m, ans));///强迫人数大于m, 取m 71 return 0; 72 }