zoukankan      html  css  js  c++  java
  • Codeforces 713E. Sonya Partymakert 题解

    Codeforces 713E. Sonya Partymaker

    Link!

    题意

    给出(n)个人在环上的位置,环长为(m),可以给每个人钦点一个方向,每个人每秒钟沿着钦定方向走一步,问全环都被人走过的最小时间。

    题解

    先二分时间(x),考虑如何判断当前时间是否合法。

    考虑破环为链,最后合并答案。

    (f[i])表示前(i)个人最远能覆盖到哪里,(p[i])表示第(i)个人的位置。

    分当前的向左还是向右讨论。

    还要考虑一种特殊情况为第(i-1,i)之间的空由(i+1)来向左填,让(i)向右扩展,(f[i])(f[i-2])转移即可。

    为什么不会有(i-1,i)之间的空由(i+2)来向左填的情况?

    答:如果(p[i+2] - x < p[i])(即(i+2)能够覆盖到(i-1,i)之间的空),那么有(p[i] + x > p[i+2]),于是(i,i+2)之间的空已经被(i)覆盖,将向左的(i+2)改为(i+1)向左,(i+2)向右一定更优。

    考虑合并时(1)向左可能覆盖到(n),会干扰状态转移,于是选取最长的一段空破环为链,取空的长度为二分上界,于是(1,n)之间不会互相覆盖。注意讨论(1)向左或向右,做两次(dp)即可。

    难点总结

    (dp)转移并非很难,难点在于观察到只会有(i+1)回头填(i-1,i)之间的空,以及选取最长的区间破环为链,避免干扰转移。

    Code

    #include<bits/stdc++.h>
    #define ll long long
    #define N 200015
    #define rep(i,a,n) for (int i=a;i<=n;i++)
    #define per(i,a,n) for (int i=n;i>=a;i--)
    #define inf 0x3f3f3f3f
    #define pb push_back
    #define mp make_pair
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define lowbit(i) ((i)&(-i))
    #define VI vector<int>
    #define all(x) x.begin(),x.end()
    #define SZ(x) ((int)x.size())
    using namespace std;
    int n,m,a[N],p[N],f[N];
    bool check(int x){
    	f[1] = 0;
    	// < - 1
    	rep(i,2,n){
    		f[i] = f[i-1];
    		if(f[i-1] >= p[i] - 1) f[i] = max(f[i],p[i] + x);
    		if(f[i-1] >= p[i] - x - 1) f[i] = max(f[i],p[i]);
    		if(i > 2 && f[i-2] >= p[i] - x - 1) f[i] = max(f[i],p[i-1] + x);
    	}
    	if(f[n] >= m - 1 - x) return 1;
    	// 1 - >
    	if(p[1] + x < p[2] - x) return 0;
    	f[2] = max(p[1] + x,p[2]);
    	rep(i,3,n){
    		f[i] = f[i-1];
    		if(f[i-1] >= p[i] - 1) f[i] = max(f[i],p[i] + x);
    		if(f[i-1] >= p[i] - x - 1) f[i] = max(f[i],p[i]);
    		if(i > 2 && f[i-2] >= p[i] - x - 1) f[i] = max(f[i],p[i-1] + x);
    	}
    	if(f[n] >= m - 1 - max(x - p[2],0)) return 1;
    	return 0;
    }
    int main(){
    	//freopen(".in","r",stdin);
    	//freopen(".out","w",stdout);
    	scanf("%d%d",&m,&n);
    	rep(i,1,n) scanf("%d",&a[i]),a[i+n] = a[i] + m;
    	sort(a+1,a+n+n+1);
    	if(n == 1){
    		printf("%d
    ",m-1);
    		return 0;
    	}
    	int pos = 2;
    	int l = 0,r;
    	rep(i,2,n+1) if(a[i] - a[i-1] > a[pos] - a[pos-1]) pos = i;
    	r = a[pos] - a[pos-1] - 1;
    	rep(i,1,n) p[i] = a[i+pos-1];
    	int st = p[1];
    	rep(i,1,n) p[i] -= st;
    	int ans = 114514;
    	while(l <= r){
    		int mid = (l+r)>>1;
    		if(check(mid)) ans = mid,r = mid-1;
    		else l = mid+1;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    upc组队赛16 Melody【签到水】
    upc组队赛16 WTMGB【模拟】
    upc组队赛15 Supreme Number【打表】
    upc组队赛15 Lattice's basics in digital electronics【模拟】
    upc组队赛15 Made In Heaven【第K短路 A*】
    upc组队赛14 As rich as Crassus【扩展中国剩余定理】
    upc组队赛14 Floating-Point Hazard【求导】
    upc组队赛14 Communication【并查集+floyd /Tarjan】
    upc组队赛14 Bus stop【签到水】
    2018/12/7 数据库事务和分布式事务
  • 原文地址:https://www.cnblogs.com/czdzx/p/14810427.html
Copyright © 2011-2022 走看看