1 条题解
-
0
思路:
我们的二分是找答案的(
俗称二分答案……),而我认为这道题真正的难点在于验证这个答案是否可行,所以说:DP 是个好东西,我们先将所有的活动点进行排序,进行预处理后,使用我们提前声明好的数组:( 表示为覆盖前 个点,用了 台大型机,最少需要的小型机台数):- 初始 。
- 从当前第一个未覆盖的 开始:
- 放小型机:跳到小型机能覆盖的点 处,小型机数量 。
- 放大型机:跳到大型机能覆盖的点 处,大型机数量 。
- 取最小值。
最后,我们只需要判断是否存在 使得 ( 代表长度),有则这个 成立,无则这个 不成立。
主函数部分十分简单,输入完后开始二分求答案,每次二分得出一个 ,判断这个 成不成立,如果成立的话,往下二分,否则往上二分,二分证明:
因为:若 可行,则 一定可行,但 不一定可行。
所以:我们这里要求的答案 就是满足 不可行的,也就是我们开头提到的最小的最大。
AC 代码:
#include<bits/stdc++.h> //万能头文件 using namespace std; const int INF=1e9; int n,m,q; vector<int> p; bool check(int w) //判断w是否可行 { int len=p.size(); vector<int> ns(len),nl(len); for(int i=0;i<len;i++) { ns[i]=upper_bound(p.begin(),p.end(),p[i]+w-1)-p.begin()-1; nl[i]=upper_bound(p.begin(),p.end(),p[i]+2*w-1)-p.begin()-1; //预处理 } int maxq=min(q,n); vector<vector<int>> dp(len+1,vector<int>(maxq+1,INF)); //声明dp数组 dp[0][0]=0; for(int i=0;i<len;i++) { for(int j=0;j<=maxq;j++) { if(dp[i][j]==INF) { continue; } dp[ns[i]+1][j]=min(dp[ns[i]+1][j],dp[i][j]+1); //求用大机子和小机子的最小值 if(j<maxq) { dp[nl[i]+1][j+1]=min(dp[nl[i]+1][j+1],dp[i][j]); } } } for(int j=0;j<=maxq;j++) { if(dp[len][j]<=m) //如果存在 { return true; } } return false; //不存在 } int main() { ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); cin>>n>>m>>q; p.resize(n); for(int i=0;i<n;i++) { cin>>p[i]; } //简单输入 sort(p.begin(),p.end()); //排序 int l=1,r=p.back()-p.front()+1,ans=r; while(l<=r) //二分答案 { int mid=(l+r)/2; if(check(mid)) //若这个w可行 { ans=mid; r=mid-1; //往下二分求最小值 } else { l=mid+1; //往上二分求可以满足条件的w的值 } } cout<<ans; //输出答案 return 0; //好习惯从今天养成 }看到这了,点个赞吧!(QAQ)……
- 1
信息
- ID
- 10146
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者