zoukankan      html  css  js  c++  java
  • 【题解】CF#713 E-Sonya Partymaker

      这题真的想了挺久的,然而到最后也还是没想到怎样处理环的情况……网上竟然也完全没有题解,无奈之下到 CF 的 AC 代码里面去找了一份膜拜了一下。感谢~

      由于觉得这题有一定的难度,自己看代码也看了比较久才理解,就记录一下吧……

      首先,不难发现一个人一定不会往返走。因为一个人之所以要往回走,理由一定是因为碰到了已经访问过的凳子(与他人的路径相撞)。我们不妨看作是这两个人灵魂交换,即两人均继续向前,而不往返。所以问题转化为在一个环上指定 n 个点,从每个点可以顺 逆时针延伸出一条长为 x 的线段,问能覆盖整个环的最小 x 值。

      显然需要二分一下。如果这个问题是在序列上的问题,我们可以 dp。设立 dp 状态 f[i][0 / 1] 表示第 i 号节点是向左 / 向右的线段,所能从起点开始连续访问的最远地点是多少。这样好像有个 bug :可以有下图中的情况出现,即第 i - 1 到第 i 号节点之间的位置由第 i + 1 号节点来覆盖。但这样没有关系,因为我们可以在 dp 到 i + 1 的位置的时候填补起 i ~ i - 1 之间的位置,并把答案更新为第 i 号节点向前延伸出来的部分。

      如果不够清晰,可以看一下代码中的转移方程。

      最难处理的就是这一个环。因为有可能第 1 号节点和第 2 号节点之间的这一段是由第 n 号节点来覆盖的。可是这样根据我们的定义,我们将一直无法更新 dp 数组。为了避免这样的一种情况,我们可以选择破环为链。断开哪一条边呢?选择断开最长的一条边,因为这条边就是答案的上界,也就是指这样断开的链上 n 号节点永远不会选择通过这条边来覆盖 1~2 之间的这一段。然后我们就只需要分类讨论一下 1 号节点是向左还是向右就可以了。

      **启示:其实这种破环为链的题目见得很多了,但还是没有做出来,是我太菜了……应该找到在环上必然不会有影响的一条边去分割成链,如51nod部落信号。

      代码(kuai的...):

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 1000000
    #define int long long 
    #define INF 99999999999LL
    int n, m, f[maxn][2], P[maxn], p[maxn];
    int ans, mx, pos; 
    
    int read()
    {
        int x = 0, k = 1;
        char c; c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    bool Check(int x)
    {
        for(int j = 0; j <= 1; j ++)
        {
            f[1][0] = j ? -INF : 0; f[1][1] = j ? x : -INF;
            if(j)
            {
                if(x + 1 >= P[2]) f[2][0] = max(P[1] + x, P[2]);
                else f[2][0] = -INF;
            }
            for(int i = j + 2; i <= n; i ++)
            {
                f[i][0] = f[i][1] = max(f[i - 1][0], f[i - 1][1]);
                if(max(f[i - 1][1], f[i - 1][0]) + 1 >= P[i]) f[i][1] = P[i] + x;
                if(P[i] - x - 1 <= f[i - 1][0]) f[i][0] = max(f[i - 1][0], P[i]);
                if(P[i] - x - 1 <= f[i - 1][1]) f[i][0] = max(f[i - 1][1], max(P[i], P[i - 1] + x));
            }
            int t = max(f[n][0], f[n][1]);
            if(j && t + 1 >= P[2] + m - x) return 1;
            else if(!j && t + 1 >= m - x) return 1;
        }
        return 0;
    }
    
    signed main()
    {
        m = read(), n = read();
        if(n == 1) { printf("%I64d
    ", m - 1); return 0; } 
        for(int i = 1; i <= n; i ++) p[i] = read();
        for(int i = 1; i <= n; i ++)
        {
            int dis; dis = p[i] - p[i - 1];
            if(i == 1) dis = p[i] + m - p[n];
            if(dis > mx) mx = dis, pos = i;
        }
        
        for(int i = 1; i <= n; i ++)
        {
            int t = i - 1 + pos; if(t > n) t -= n;
            P[i] = p[t]; P[i] -= p[pos];
            if(P[i] < 0) P[i] += m;
        }
        
        int l = 0, r = m - 1;
        while(l <= r)
        {
            int mid = (l + r) >> 1;
            if(Check(mid)) ans = mid, r = mid - 1;
            else l = mid + 1;
        }
        printf("%I64d
    ", ans);
        return 0;
    }
  • 相关阅读:
    ubuntu安装与卸载java
    linux ubuntu 用户名,主机名,密码修改,增加用户,删除用户
    linux中sudo fdisk -l报错:GPT PMBR size mismatch will be corrected by write错误
    VM VirtualBox虚拟机vdi扩大磁盘空间容量
    WinSCP传输文件到虚拟机linux报错:SSH2_MSG_CHANNEL_FAILURE for nonexistent channel 0
    parallel python多进程集群模式
    zookeeper报错:ERROR [main:QuorumPeerMain@86]
    hive启动报错:Exception in thread "main" java.lang.RuntimeException: com.ctc.wstx.exc.WstxParsingException: Illegal character entity: expansion character (code 0x8 at
    3.数据链路层
    2.物理层
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/9930132.html
Copyright © 2011-2022 走看看