P1053 [NOIP2005 提高组] 篝火晚会

->(   )可以不连续 + 移动 编号是 b1,b2.....

-> 相同数的个数最多的 可以通过 旋转 +圈可以反转移动

-> 其他的数可以 通过编号 连成一个圈 与原来的 圈一样

-> 构造圈+自己的语言做+翻译->count

! 圈的性质 ->反转+移动

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int Maxn=50010;
int Dv1[Maxn],Dv2[Maxn];
//分别表示与1,2,...,n和n,n-1,...,2,1的差值
int vis[Maxn];
int c[Maxn];//目标链
int l1[Maxn],l2[Maxn];
int pd=1,n,ans=0;
inline int read()//读入优化
{
    int fl=1,rt=0; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') fl=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){rt=rt*10+ch-'0'; ch=getchar();}
    return fl*rt;
}
void Build()//建目标链
{
    c[1]=1; c[2]=l1[1]; vis[c[1]]=vis[c[2]]=1;
    for(int i=2;i<=n-1;i++)
    {
        if(c[i-1]==l1[c[i]]) c[i+1]=l2[c[i]],vis[c[i+1]]=1;  
        else if(c[i-1]==l2[c[i]]) c[i+1]=l1[c[i]],vis[c[i+1]]=1;
        else 
        {
            pd=0;
            printf("-1\n"); return ;
        }
    }
    for(int i=1;i<=n;i++) if(!vis[i]) pd=0,printf("-1\n");
    //c[n] l1/l2 一定是 c[n-1]  且 c[n] l2/l1 一定是c[1]  
    if((c[1]==l1[c[n]]&&c[n-1]!=l2[c[n]])||(c[1]!=l1[c[n]]&&c[n-1]==l2[c[n]])) pd=0,printf("-1\n");
    else if((c[1]==l2[c[n]]&&c[n-1]!=l1[c[n]])||(c[1]!=l2[c[n]]&&c[n-1]==l1[c[n]])) pd=0,printf("-1\n");
}
void count()//求答案
{
    for(int i=1;i<=n;i++)
    {
        Dv1[(c[i]-i+n)%n]++;
        Dv2[(c[n-i+1]-i+n)%n]++;
    }
    for(int i=0;i<=n-1;i++) ans=max(ans,max(Dv1[i],Dv2[i]));//最大的不用调整的数
    printf("%d\n",n-ans);//cause 移动 编号是 b1,b2...bm 的位置 -> 任意->
}
void read_ini()
{
    n=read();
    for(int i=1;i<=n;i++) l1[i]=read(),l2[i]=read();
    Build();
    if(pd) count();
}
int main()
{
    read_ini();
    return 0;
}
View Code

 

posted @ 2023-07-12 08:20  JMXZ  阅读(25)  评论(0)    收藏  举报