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

题目描述

传送门

题解

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

代码

#include
#include
#include
#include
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;i1; 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);
}

你可能感兴趣的:(题解,NOIP,数学相关,模拟)