[NOIP2005][CODEVS1106]篝火晚会(模拟+数学相关)

来源:互联网 发布:知乎 hiv携带者 编辑:程序博客网 时间:2024/04/28 02:59

题目描述

传送门

题解

首先知道从初状态转移到末状态和从末状态转移到初状态是一样的,那么我们可以构造出末状态,然后计算转移到初状态的最小代价。
可以知道转移的代价一定为不在应该在的位置上的人的数量,那么就要使最多的人在位置上。考虑到环的情况,我们假设对于一个数i的目标是将它放到i这个位置,那么如果有若干个数距离各自的目标需要移动的步数相等的话,说明令其中的一个数在位置上,那么其他的数也在位置上。假设这些数是一个组,找出有最多人数的那个组,那么ans=n-组内人数。
注意没有规定是顺时针还是逆时针,所以要正反做两次。

代码

#include<iostream>#include<cstring>#include<cstdio>#include<queue>using namespace std;const int max_n=5e4+5;int n,L,R,t,ans;int a[max_n],b[max_n],l[max_n],r[max_n],pre[max_n],nxt[max_n];bool flag,vis[max_n];int cnt1[max_n],cnt2[max_n];queue <int> q;int main(){    scanf("%d",&n);    for (int i=1;i<=n;++i) scanf("%d%d",&l[i],&r[i]);    for (int i=2;i<=n;++i) pre[i]=i-1; pre[1]=n;    for (int i=1;i<n;++i) nxt[i]=i+1; nxt[n]=1;    flag=true;    vis[1]=vis[pre[1]]=vis[nxt[1]]=true; a[1]=1; a[pre[1]]=l[1]; a[nxt[1]]=r[1];    while (!q.empty()) q.pop(); q.push(pre[1]); q.push(nxt[1]);    while (!q.empty())    {        int now=q.front(); q.pop();        L=l[a[now]]; R=r[a[now]];        if (!vis[pre[now]]&&vis[nxt[now]])        {            if (a[nxt[now]]==L)            {                a[pre[now]]=R;                vis[pre[now]]=true;                q.push(pre[now]);            }            else if (a[nxt[now]]==R)            {                a[pre[now]]=L;                vis[pre[now]]=true;                q.push(pre[now]);            }            else            {                flag=false;                break;            }        }        else if (vis[pre[now]]&!vis[nxt[now]])        {            if (a[pre[now]]==L)            {                a[nxt[now]]=R;                vis[nxt[now]]=true;                q.push(nxt[now]);            }            else if (a[pre[now]]==R)            {                a[nxt[now]]=L;                vis[nxt[now]]=true;                q.push(nxt[now]);            }            else            {                flag=false;                break;            }        }        else if (vis[pre[now]]&&vis[nxt[now]])        {            if (a[pre[now]]==L)            {                if (a[nxt[now]]!=R)                {                    flag=false;                    break;                }            }            else if (a[nxt[now]]==L)            {                if (a[pre[now]]!=R)                {                    flag=false;                    break;                }            }            else            {                flag=false;                break;            }        }    }    if (!flag)    {        printf("-1\n");        return 0;    }    for (int i=1;i<=n;++i)    {        t=(a[i]-i+n)%n;        cnt1[t]++;        ans=max(ans,cnt1[t]);        t=(a[n-i+1]-i+n)%n;        cnt2[t]++;        ans=max(ans,cnt2[t]);    }    printf("%d\n",n-ans);}
0 0
原创粉丝点击