篝火晚会(NOIP 2005 提高组 第三题)

来源:互联网 发布:中文域名的好处 编辑:程序博客网 时间:2024/04/28 14:43

篝火晚会(NOIP 2005 提高组 第三题)
题目概述
一共有n个同学,编号从1到n。一开始,同学们按照1,2,……,n的顺序坐成一圈,实际上每个人都有两个最希望相邻的同学。每一个命令的形式如下:这里m的值是由佳佳决定的,每次命令m的值都可以不同。这个命令的作用是移动编号是b1,b2,…… bm的这m个同学的位置。要求b1换到b2的位置上,b2换到b3的位置上,……,要求bm换到b1的位置上。执行每个命令都需要一些代价。我们假定如果一个命令要移动m个人的位置,那么这个命令的代价就是m。我们需要佳佳用最少的总代价实现同学们的意愿,如果无论怎么调整都不能符合每个同学的愿望,则输出-1。
数据规模
3 <= n <= 50000
思路
这个题比较难。
想到正解思路并不容易,正解的第一点就是最后的答案事实上应该是目标序列和原序列不相同的数的最小值。简要证明一下:假设目标序列上的元素X和原序列相同位置不相同,那么就只需要1个代价来把它恢复到正确的位置上,其它的亦然。
然后我们就想到了这样一个思路,目标序列构造好了之后,由于它的开头不一定,有2*N种序列需要比较,我们就逐一比较,这就是O(N^2)的算法。
显然对于50000的数据,这样是不会过的。那么还有一个思路,就是求原序列和目标序列之间的距离,并将之记录下来,然后就是O(N)的时间复杂度,然后输出N-min(count[length])啦。

#include<iostream>using namespace std;int i,j,m,n,temp;int a[50001],x[50001],y[50001];int gs[50001],gs2[50001];int r(){    int ans=0,f=1;    char ch;    while(ch<'0'||ch>'9')    {        if(ch=='-')        f=-1;        ch=getchar();    }    while(ch>='0'&&ch<='9')    {        ans*=10;        ans+=ch-'0';        ch=getchar();    }    return ans*f;}int main(){    n=r();    for(i=1;i<=n;i++)    {        x[i]=r(),y[i]=r();    }    a[1]=1,a[2]=x[1];    for(i=3;i<=n;i++)    {        if(x[a[i-1]]==a[i-2]) a[i]=y[a[i-1]];        else a[i]=x[a[i-1]];    }    int le,ri;    for(i=1;i<=n;i++)    {        le=i-1;        ri=i+1;        if(!le)        le=n;        if(ri==n+1)        ri=1;        if((x[a[i]]!=a[ri]||a[le]!=y[a[i]])&&        (y[a[i]]!=a[ri]||a[le]!=x[a[i]]))        {            cout<<-1;            return 0;        }    }    int dis1,dis2;    for (i=1; i<=n; i++)    {        dis1=(a[i]-i+n)%n;        dis2=(a[i]+i-1)%n;        gs[dis1]++;        gs2[dis2]++;    }    int ans=0;    for (i=0; i<n; i++)     {        if (ans<gs[i]) ans=gs[i];        if (ans<gs2[i]) ans=gs2[i];    }    cout<<n-ans;    return 0;}

这里写图片描述