P3853 [TJOI2007]路标设置
传送门
思路:
类似于数列分段的二分查找答案。设目前的 mid 是一个最小的“空旷指数”,那么在 sum 数组(路标数组)里每两个相邻间的路标距离一定要小于等于目前的 mid , 如果大于,那就必须使用一些路标去填补这个距离。
两个路标之间距离大于 mid 又要分为两种情况:①两路标之间距离不能整除 mid ,则要放置 ( sum [ i+1 ] -sum [ i ] )/mid 个路标。②如果两路标之间距离能够整除 mid 则所放置的路标数要 -1 。
每一次二分判断 mid 距离是否满足 cnt ≤ k :①如果≤, 则 mid 的距离可以再缩小;②如果>,则 mid 的距离要放大。
AC代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cmath> #include<cstring> #include<string> #include<cstdlib> #include<queue> #include<vector> #include<deque> #include<stack> #include<map> #include<set> using namespace std; #define maxn 100100 long long sum[maxn],l,r,mid,cnt;//cnt记录在mid条件下,所需的路标数 long long len,n,k; inline long long read() { long long kr=1,xs=0; char ls; ls=getchar(); while(!isdigit(ls)) { if(ls=='-') kr=-1; ls=getchar(); } while(isdigit(ls)) { xs=(xs<<1)+(xs<<3)+(ls^48); ls=getchar(); } return kr*xs; } inline bool check(long long u) { cnt=0; for(long long i=1;i<=n+1;i++) { if(sum[i]-sum[i-1]>u)//如果两个路标之间的距离大于mid { cnt+=(sum[i]-sum[i-1])/u;//所需的路标数增加 if((sum[i]-sum[i-1])%u==0)//如果能够整除 cnt--;//路标数 -1 } } if(cnt<=k) return true; return false; } int main() { len=read();n=read();k=read(); for(long long i=1;i<=n;i++) sum[i]=read(); sum[0]=0;sum[n+1]=len; l=0;r=sum[n]; while(l<r) { mid=l+r>>1; if(check(mid)) r=mid; else l=mid+1; }//日常二分 printf("%lld\n",l);//l为最终的mid return 0; }