[NOIp2005]篝火晚会

Description

Luogu1053

Solution

首先要发现一个事实:对于每个不再正确位置上的人,我们都要花费1的代价来让他正确(然而我没有发现…)。

TODO:证明这个事实。

然后就可以转化问题为:最多有多少个人不用动。那么那些人不用动呢?就是那些与目标位置距离相等的人的集合,即断环为链之后,不用右移就在目标位置的人、右移一次到达目标位置的人、右移两次……这几群人。他们之中最多的那群就是最多有多少个人不用移动。

如何生成目标链呢?直接模拟就好了。不过要注意如果“我爱的人不爱我”的话就gg了。

Code

#include <cstdio>
#include <cstring>

const int N = 50010;

int fr[N][2], per[N];
int n;
int spin[N];

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) scanf("%d%d", &fr[i][0], &fr[i][1]);
    // 计算完美的序列  
    for (int i = 1; i <= n; ++i) {
        if ((i != fr[fr[i][1]][0] && i != fr[fr[i][1]][1]) 
        || (i != fr[fr[i][0]][0] && i != fr[fr[i][0]][1])) {
            puts("-1");
            return 0;
        }
    }
    per[1] = 1; per[2] = fr[1][0]; per[n] = fr[1][1];
    for (int i = 2; i < n; ++i) {
        if (per[i-1] == fr[per[i]][0]) {
            per[i+1] = fr[per[i]][1];
        } else {
            per[i+1] = fr[per[i]][0];
        }
    }
    // 由于我们恢复每个点的代价为1,所以找出哪些点不用动,剩下的就是答案。
    int ans = 0x3f3f3f3f;
    for (int i = 1; i <= n; ++i) {
        if (++spin[(per[i] - i + n) % n] > n - ans) {
            ans = n - spin[(per[i] - i + n) % n];
        }
    }   
    memset(spin, 0, sizeof spin);
    for (int i = 1; i <= n; ++i) {
        if (++spin[(per[i] + i - 1) % n] > n - ans) {
            ans = n - spin[(per[i] + i - 1) % n];
        }
    }
    printf("%d\n", ans);
    return 0;
}

转载于:https://www.cnblogs.com/wyxwyx/p/noip20053.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值