zoukankan      html  css  js  c++  java
  • CF713E

    CF713E [* easy]

    有一个长度为 (m) 的环,最初有 (n) 个点上有人。

    每秒可以让所有人都走一步(初始选定所有人的方向)

    求使得所有点都被走过的最短时间。

    (nle 10^5,mle 10^9)

    Solution

    我们发现答案的上界是最长的段。

    考虑二分答案,然后 check

    如果是序列的话,我们可以这样 dp,设 (f_i) 表示考虑到第 (i) 个点,

    如果 (f_{i-1}<a_i),那么当前点必须往前走,否则往后走。

    然而有一个问题,有可能是 (i-1) 帮忙覆盖了,然后 (i) 就只需要往前覆盖。

    不难发现我们一定没有必要让 (i-2) 往后覆盖并以此使得 (i) 往前走,因为此时 (i-1) 一定可以往后走。

    所以分类讨论一下即可。

    然后我们发现环非常的不好处理。

    但是最长的段一定是会被断开的。

    所以枚举一下他两边的点是如何 choose 的,然后断环为链,你就 win 了,要注意如果他往右走,那么他的下一个可以往前走。

    复杂度 (mathcal O(nlog m))

    (Code:)

    #include<bits/stdc++.h>
    using namespace std ;
    #define Next( i, x ) for( register int i = head[x]; i; i = e[i].next )
    #define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
    #define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )
    #define re register
    int gi() {
    	char cc = getchar() ; int cn = 0, flus = 1 ;
    	while( cc < '0' || cc > '9' ) {  if( cc == '-' ) flus = - flus ; cc = getchar() ; }
    	while( cc >= '0' && cc <= '9' )  cn = cn * 10 + cc - '0', cc = getchar() ;
    	return cn * flus ;
    }
    const int N = 2e5 + 5 ;  
    int n, m, a[N], b[N], dp[N], d, id ; 
    bool check(int x) {
    	rep( j, 0, 1 ) {
    		rep( i, 0, n ) dp[i] = -m ;
    		int Ed = m + b[1] - j * x, fs = Ed ; //j = 0 means after
    		dp[1] = b[1] + (j ^ 1) * x ;
    		if(!j) fs = m + b[2] - x - 1, dp[2] = max( b[2], b[1] + x ) ; 
    		rep( i, (2 + (j ^ 1)), n ) {
    			if( dp[i - 2] >= b[i] - x - 1 ) dp[i] = b[i - 1] + x ;
    			if( dp[i - 1] >= b[i] - x - 1 ) dp[i] = max(dp[i], b[i]) ;
    			if( dp[i - 1] >= b[i] - 1 ) dp[i] = b[i] + x ;
    		}
    		if( dp[n] >= min( Ed - 1, fs ) ) return 1 ;
    	} return 0 ; 
    }
    signed main()
    {
    	m = gi(), n = gi() ; 
    	rep( i, 1, n ) a[i] = gi(), a[i + n] = a[i] + m ;
    	if( n == 1 ) { printf("%d
    ", m - 1 ) ; exit(0) ; }
    	rep( i, 2, n + 1 ) {
    		int di = a[i] - a[i - 1] ; 
    		if( d < di ) d = di, id = i ; 
    	}
    	rep( i, 1, n ) b[i] = a[i + id - 1] ; 
    	int l = 0, r = d, ans = d ; 
    	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 ;
    }
    
  • 相关阅读:
    MySQL 8 新特性之Clone Plugin
    哈尔滨工业大学(威海)第九届ACM程序设计竞赛
    我回来了
    正则表达式(五):正则表达式的高阶使用
    正则表达式(四):正则表达式中的分组的概念
    正则表达式(三):正则表达式中的重复
    正则表达式(二):正则表达式的元字符
    正则表达式(一):正则表达式的概念
    Android NDK 跨平台构建工具 CMake 使用笔记
    字节序问题之大小端模式讲解
  • 原文地址:https://www.cnblogs.com/Soulist/p/13793124.html
Copyright © 2011-2022 走看看