题解

130 条题解

  • 0
    @ 2006-09-26 17:18:47

    每组数据确定两组相对位置关系,并且这两组互为镜像。

    对于某一种排列方式,不在需要位置上的人数即为当前状态到目标状态的最小代价。

    先找出其中一种排列方式。由于目标状态可以通过旋转而使得部分人的变化次数减少,所以找出每个人通过某一固定方向旋转到达目标位置的旋转次数。找到某一次数,使得拥有这个次数的人数最多。那么,通过旋转这一最多人拥有的次数,即可使得尽可能多的人不通过交换直接到达目标位置。于是,不拥有这一旋转次数的人数即为这一状态下的最小代价。

    然后,用现在的目标状态找出其镜像状态,并且用上述方法再找一遍最小代价,与前面的结果比较,较小值即为答案。

    另外,题目中会出现一些无解的情况:

    1.某个人被“要”的次数多于两次,也就是说有多于两个的人想要与他(她)邻座,那么无解。

    2.根据要求得出的目标状态为多于一个的环,也无解。

  • 0
    @ 2006-07-28 17:27:36

    提交了若干次……残念……

  • 0
    @ 2006-07-28 16:26:28

    这题比赛时真有人ac?

    真不好想

    为什么得开longint啊?

  • 0
    @ 2006-07-25 13:29:56

    排列本质不同的只有二种 正着和反着的

    检验几个人不在位置上用数学方法:)模拟法超时的

  • 0
    @ 2006-07-23 04:37:47

    注意别误解题意 b1,b2....bm并不指连续位置上的数

  • 0
    @ 2006-01-26 09:21:51

    可以用群论证明:如果有k个人不在自己的位置上,那么要且仅要k的代价,即可使这些人归位

    剩下的..很简单了吧...

  • -1
    @ 2015-09-12 23:20:54

    qiadafei

    Vijos 已自动进入夜间模式。关闭夜间模式(仅本次会话有效)
    当前位置:/home/题库/P1008 篝火晚会/题解个人通过/递交:0/1(0%)
    未递交
    篝火晚会
    发表题解

    需要更丰富的内容输出?编辑器快速入门 | Markdown详细帮助[Ctrl+Enter] 预览

    0

    回复 liuhehe发表于2015-07-31 20:10
    include<iostream> include<cstdio> include<cstring> include<cstdlib>
    using namespace std;
    const int maxn=50005;
    int f[maxn];
    int wz[maxn];
    int py[maxn][2];
    int numn;
    void dfs(int cur,int now)
    {
    if(wz[py[now][1]]==-1)
    {
    wz[py[now][1]]=(cur+1)%numn;
    f[cur+1]=py[now][1];
    dfs(cur+1,py[now][1]);
    }
    else if(wz[py[now][0]]==-1)
    {
    wz[py[now][0]]=(cur+1)%numn;
    f[cur+1]=py[now][0];
    dfs(cur+1,py[now][0]);
    }
    else if(cur==numn-1)return;
    else {printf("-1\n");exit(0);}
    }
    void work()
    {
    int c1[maxn],c2[maxn];
    memset(c1,0,sizeof(c1));
    memset(c2,0,sizeof(c2));
    for(int i=0;i<numn;i++)
    {
    c1[(numn+i-f[i]+1)%numn]++;
    c2[(numn+i+f[i]-1)%numn]++;
    }
    int maxx=-1;
    for(int i=0;i<numn;i++)
    {
    maxx=max(maxx,c1[i]);
    maxx=max(maxx,c2[i]);
    }
    printf("%d\n",numn-maxx);
    }
    int main()
    {
    scanf("%d",&numn);
    memset(wz,-1,sizeof(wz));
    for(int i=1;i<=numn;i++)scanf("%d%d",&py[i][0],&py[i][1]);
    f[0]=1;wz[1]=0;
    dfs(0,1);
    for(int i=0;i<numn;i++)
    {
    // printf("%d ",f[i]);printf("\n");
    if(!(f[(i+numn-1)%numn]==py[f[i]][0]||f[(i+numn-1)%numn]==py[f[i]][1]))
    {
    printf("-1\n");exit(0);
    }
    if(!(f[(i+numn+1)%numn]==py[f[i]][0]||f[(i+numn+1)%numn]==py[f[i]][1]))
    {
    printf("-1\n");exit(0);
    }
    }
    work();
    return 0;
    }
    看了半天题解才搞会。。。关键是题目说的很含糊!!!
    主要就是先根据每个人要求建环
    然后定一个人原地不动,剩下的人做调整,这里有n种情况
    接着每种情况可以通过简单的优化通过O(1)时间算出代价

    0

    回复 whxc049发表于2015-07-05 11:02
    0
    回复 yingjiangyu发表于2015-02-15 21:55
    打‘Wrong!’有50分。。
    0
    回复 东大微雕发表于2015-02-07 15:20
    这道题真是太好了。奇妙无穷。
    include<iostream> include<string.h> include<stdio.h>
    using namespace std;
    int a[50005];
    int size;
    void go(){
    int i, j;
    int ans = 0;
    int dis[50005];
    memset(dis, 0, sizeof(dis));
    for (i = 1; i <= size; i++){
    int d = (a[i] - i + size) % size;
    dis[d]++;
    }
    for (i = 0; i < size; i++){
    if (ans < dis[i])
    ans = dis[i];
    }
    memset(dis, 0, sizeof(dis));
    for (i = 1; i <= size; i++){
    int d = (a[size+1-i]-i+size) % size;
    dis[d]++;
    }
    for (i = 0; i < size; i++){
    if (ans < dis[i])ans = dis[i];
    }
    cout << size-ans << endl;
    }
    int main(){
    freopen("in.txt", "r", stdin);
    int neibor[50005][2];
    int i;
    cin >> size;
    for (i = 1; i <= size; i++){
    scanf("%d%d",&neibor[i][0],& neibor[i][1]);
    }
    bool used[50005];
    memset(used, 0, sizeof(used));
    a[1] = 1;
    used[1] = true;
    for (i = 2; i <= size; i++){
    int last = a[i - 1];
    if (!used[neibor[last][0]]){
    a[i] = neibor[last][0];
    used[a[i]] = true;
    }
    else if (!used[neibor[last][1]]){
    a[i] = neibor[last][1];
    used[a[i]] = true;
    }
    else {
    cout << -1 << endl;
    return 0;
    }
    }
    if (neibor[1][0] != a[size] && neibor[1][1] != a[size]){
    cout << -1 << endl;
    return 0;
    }
    go();
    return 0;
    }
    0
    回复 3516发表于2014-07-30 08:59
    include<stdio.h>
    include<string.h>
    int data[50001][2],shi[50001],a[50001];
    int main()
    {
    int n,i,j,qian,hou; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d%d",&data[i][0],&data[i][1]); } a[1]=1;shi[a[1]]=1 for(i=2;i<=n;i++) { qian=data[a[i-1]][0]; hou=data[a[i-1]][1]; if(shi[qian]==0) { a[i]=qian; shi[qian]=1; } else if(shi[hou]==0) { a[i]=hou; shi[hou]=1; } else { printf("-1"); return 0; } } int temp=0,max=0; memset(shi,0,sizeof(shi)); for(i=1;i<=n;i++) { temp=(n+a[i]-i+1)%n; shi[temp]++; } for(i=0;i<n;i++) { if(max<shi[i]) { max=shi[i]; } } memset(shi,0,sizeof(shi)); for(i=1;i<=n;i++) { temp=(n+a[n-i+1]-i+1)%n; shi[temp]++;
    }
    for(i=0;i<n;i++)
    {
    if(max<shi[i])max=shi[i];
    }
    printf("%d",n-max);
    }
    0
    回复 S.Y.F发表于2013-08-31 14:04
    题解
    1111111129回复于2014-08-13 11:52
    orzorzorz
    0
    回复 S.Y.F发表于2013-07-29 16:55
    从10、到30、到100。。。。。。
    题解:http://blog.163.com/syf_light_feather/blog/static/223755067201362945326756/
    0
    回复 vcvycy发表于2013-06-30 00:56
    20 30 40 50 70 分都有~泪流满面.
    Accepted
    100
    772 2
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:55:05
    Wrong Answer
    70
    613 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:53:24
    Wrong Answer
    70
    686 2
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:45:35
    Wrong Answer
    70
    856 2
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:42:12
    Wrong Answer
    70
    803 2
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:37:26
    Wrong Answer
    70
    882 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:22:39
    Wrong Answer
    70
    1145 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:20:30
    Wrong Answer
    10
    733 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:11:30
    Wrong Answer
    50
    723 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:04:20
    Wrong Answer
    50
    781 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:55:49
    Wrong Answer
    40
    656 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:49:49
    Wrong Answer
    40
    758 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:44:00
    Time Exceeded
    30
    7160 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:38:22
    Time Exceeded
    20
    7135 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:35:08
    0
    回复 SEX丶Elope发表于2013-02-16 10:10
    点击查看程序源码+详细题解
    cuichen回复于2014-09-09 09:24
    怎么又是你??你有什么企图?骗访问量???垃圾!
    0
    回复 qyjubriskxp发表于2010-07-09 21:31
    再一次体会到c++流的悲剧,秒杀和3s原来只是输入方式的不同,杯具~~
    yuyilahanbao回复于2014-01-24 11:47
    从c转到c++第一次不AC(除去忘记把语言有c改为c++的)就是因为c++输入输出的问题
    从那次起,我的c++的输入都是用scanf和printf了
    因为
    保险
    安全
    我记不清cin是<<还是>>
    printf和scanf相对更灵活
    ....
    0
    回复 slm发表于2010-03-16 18:27
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    嘿嘿
    0
    回复 superyoi发表于2009-11-10 11:50
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    superyoi killed p1008 with a headshot by awp
    0
    回复 200853349发表于2009-11-10 10:49
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    当我看到众位神牛打出“置换群”三个字后,我在黑书百度GOOGLE维基百科逛了得有一个半小时多然后回来AC了。。。
    思路和strini神牛的基本一样。
    0
    回复 sinb发表于2009-11-09 13:02
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    其实很简单,不要想复杂了,先是想办法构成,然后用置换群的方法即可ac。
    0
    回复 香蕉派发表于2009-11-06 11:29
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    虽然不懂什么叫置换群,但是思路还是很清晰的。。
    0
    回复 赏金神侠PPF发表于2009-11-05 11:45
    一星星纪念~
    0
    回复 strini发表于2009-10-30 22:11
    根据群论原理,任何置换群都可以分解为若干个循环节。显然,这道题目就是冲着这点来的。因为如果某循环的长度为L,那么本题中只需要代价为L的操作。注意,这里的L!=1,这是因为只有一个人的循环节不需要任何代价的操作。到这里才只能拿三十分,因为圈是可以旋转的,常规方法需要O(n^2)才能解决。不妨这里以编号为1的人为基准,定义每个人到自己应该所在位置的距离。距离不超过n-1。可以通过最大值来寻找能在自己位置上的最多的人数(因为距离为x的人在旋转x次后转到自己的位置上),那么在比较好的情况下,可以优化到O(n)。
    TIME: 1H
    SUBMIT:
    1 70 Error: 发现希望相邻是不精确的,于是改了个搜索方向。(以为题目给定的是按照左右方向,白书说过不能“假定”!)。
    2 90 Error: 终于明白要取两个搜索方向的最大值。
    3 Accepted.
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 skykey发表于2009-10-29 17:58
    include<iostream>
    using namespace std;
    int n;
    int a[50001],b[50001],c[50001];
    int aim[50001];
    void G_MAP()
    {
    bool mark[50001]={false};
    int p=1,r=1;
    while(p<=n)
    {
    aim[p]=r;mark[r]=true;p++;
    if(!mark[a[r]])r=a[r];
    else if(!mark[b[r]])r=b[r];
    else if(p<=n){cout<<-1;exit(0);}
    }
    }
    int COMPULATE()
    {
    int max=0;
    int t;
    int record[2][50001];
    for(int i=1;i<=n;i++)record[0][i]=record[1][i]=0;
    for(int i=1;i<=n;i++)
    {
    if((t=aim[i]-i)<0)t+=n; record[0][t]++; if(record[0][t]>max)max=record[0][t];
    if((t=aim[i]-(n+1-i))<0)t+=n; record[1][t]++; if (record[1][t]>max)max=record[1][t];
    }
    return max;
    }
    int main()
    {
    cin>>n;
    for(int i=1;i<=n;i++)
    {scanf("%d%d",&a[i],&b[i]);c[a[i]]++;c[b[i]]++;}
    for(int i=1;i<=n;i++)if(c[i]!=2){cout<<-1;return 0;}
    G_MAP();
    int T=COMPULATE();
    cout<<n-T;
    }
    0
    回复 song19931218发表于2009-10-27 20:11
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    考虑两种情形(貌似这两种情形很像,但又真的不同,后来才想起,在化学的手性碳原子那部分遇到过类似情况。。。)
    然后就是运用置换群的知识
    0
    回复 Aries_C发表于2009-10-25 08:24
    正反两遍...两遍...<幽幽的声音飘远..>
    不然就是70分啊...
    不看题解的情况下竟然自己想到了...
    记得以前老师给我们做过这题的..细节什么的现在做又忘记了..唉..
    0
    回复 国防安全员001发表于2009-10-21 22:00
    Flag   Accepted
    题号   P1008
    类型(?)   模拟
    通过   1701人
    提交   4835次
    通过率   35%
    难度   3
    题目表述有问题。。
    0
    回复 liubosen发表于2009-10-21 21:50
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    yaaaayyayayyayayayayayayayayayayayayayayayyaayayayayayayyaayayayay
    var
    n,max,i:longint;
    a,b,c,d:array[0..50001] of longint;
    begin
    readln(n);
    for i:=1 to n do
    readln(a[i],b[i]);
    c[1]:=1;
    c[2]:=a[1];
    for i:=3 to n do
    if c=a[c] then c[i]:=b[c]
    else
    if c=b[c] then c[i]:=a[c]
    else begin
    writeln(-1);
    halt
    end;
    if c[n]<>b[1] then
    begin
    writeln(-1);
    halt
    end;
    fillchar(d,sizeof(d),0);
    for i:=1 to n do
    inc(d[(c[i]-i+n)mod n]);
    for i:=0 to n-1 do
    if d[i]>max then max:=d[i];
    fillchar(d,sizeof(d),0);
    for i:=1 to n do
    inc(d[(c[i]+i-1)mod n]);
    for i:=0 to n-1 do
    if d[i]>max then max:=d[i];
    writeln(n-max);
    end.
    0
    回复 lishunzhi发表于2009-10-21 00:11
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    置换群,但建环是重点
    0
    回复 zebra发表于2009-10-03 09:48
    include <iostream> include <cassert>
    using namespace std;
    long N,seq[50001],p=1;
    class
    {
    private:
    long nbr[50001][3];
    bool flag[50001];
    bool isnbr(long v1,long v2)
    {
    for(int i=1;i<=nbr[v1][0];i++)
    if(nbr[v1][i]==v2)
    return true;
    return false;
    }
    public:
    bool AddE(long v1,long v2)
    {
    if(isnbr(v1,v2))
    return true;
    else
    if(nbr[v1][0]==2||nbr[v2][0]==2)
    return false;
    else
    {
    nbr[v1][++nbr[v1][0]]=v2;
    nbr[v2][++nbr[v2][0]]=v1;
    return true;
    }
    }
    void dfs(long i)
    {
    assert(!flag[i]);
    flag[i]=true,seq[p++]=i;
    for(int j=1;j<=nbr[i][0];j++)
    {
    if(!flag[nbr[i][j]])
    {
    dfs(nbr[i][j]);
    break;
    }
    }
    }
    }G;
    long solve()
    {
    long cnt1[50001]={0},cnt2[50001]={0},ans=0;
    for(int i=1,a,b;i<=N;i++){
    a=seq[i]-i;
    if(a<0) a+=N; b=seq[i]-(N+1-i); if(b<0) b+=N; if(++cnt1[a]>ans) ans=cnt1[a];
    if(++cnt2>ans) ans=cnt2;
    }
    return N-ans;
    }
    int main()
    {
    cin >> N;
    for(int i=1,nbr1,nbr2;i<=N;i++)
    {
    cin >> nbr1 >> nbr2;
    if(!G.AddE(i,nbr1)||!G.AddE(i,nbr2))
    {
    cout << -1 << endl;
    return 0;
    }
    }
    G.dfs(1);
    cout << solve() << endl;
    system("pause");
    return 0;
    }
    0
    回复 -117-Join发表于2009-09-18 21:29
    哪位大牛帮忙看看我错哪里了
    它只得90分
    program fire;
    type
    arr=record
    l,r:longint;
    end;
    var
    num:array[1..50000]of longint;
    a:array[1..50000]of arr;
    b:array[1..50000]of longint;
    i,k,j,n:longint;
    begin
    readln(n);
    for i:=1 to n do
    readln(a[i].l,a[i].r);
    b[1]:=1;
    b[n]:=a[1].l;
    if a[b[n]].l=b[1]then b[n-1]:=a[b[n]].r
    else b[n-1]:=a[b[n]].l;
    i:=n-1;
    b[2]:=a[1].r;
    j:=2;
    while j<=i do
    begin
    if b<>a[b[i]].l then b:=a[b[i]].l
    else b:=a[b[i]].r;
    dec(i);
    if b[j-1]<>a[b[j]].r then b[j+1]:=a[b[j]].r
    else b[j+1]:=a[b[j]].l;
    inc(j);
    end;
    for i:=2 to n-1 do
    if(b<>a[b[i]].r)and(b<>a[b[i]].l)or(b<>a[b[i]].r)and(b<>a[b[i]].l)then
    begin
    write(-1);
    halt
    end;
    if(b[n]<>a[b[1]].l)and(b[n]<>a[b[1]].r)or(b[2]<>a[b[1]].l)and(b[2]<>a[b[1]].r)or(b[1]<>a[b[n]].l)and(b[1]<>a[b[n]].r)or(b[n-1]<>a[b[n]].l)and(b[n-1]<>a[b[n]].r)then
    begin
    write(-1);
    halt
    end;
    num[0]:=0;
    for i:=1 to n do
    begin
    a[b[i]].l:=i;
    num[i]:=0;
    end;
    for i:=1 to n do
    if a[i].l-i>=0 then inc(num[a[i].l-i])
    else inc(num[a[i].l-i+n]);
    j:=0;
    for i:=0 to n do
    if num[i]>j then j:=num[i];
    write(n-j);
    end.
    写的有点长
    0
    回复 fs302发表于2009-09-17 20:13
    分析:学一个好思想:正难则反!由顺序到乱序我们很难快速找到,但是我们知道如何从乱序变为顺序!解决本题利用了组合数学中置换群的思想。
    从第一个人处断开,将圆环的问题转化为序列的问题。如果可以,求出目标序列。求出目标序列复杂度O(n).
    求出目标序列右移0至n-1位置时,不需要移动的人数。将目标序列反转,再求出目标序列右移0至n-1位置时,不需要移动的人数。求不需要移动的人数最大等价于求需要移动的人数最小。复杂度O(n)。
    更详细的说:
    引进“相对有序”这个概念,当两个人满足C[j]-C[i]==j-i时,两个相对有序。
    题目要求最小的总代价,但是我们可以考虑倒过来想,要求最小的总代价亦即求最多有多少人不用移动,亦即相对有序。
    然后我们引进一个辅助变量T=C-I,{C-I>=0},T=C[i]-I+N,{C[i]-I<0},那么这个T[i]有什么意义呢?我们知道初始状态的编号是1-N,而目标状态是C[1]-C[N],那么C-I便是从目标状态到初始状态顺时针所要移动的距离,那么如果那么T值相等的两个同学则是相对有序的,亦即不用移动,我们只要找出最大的T然后N-Max(T)就是得到的结果,但是这样还不够,因为刚刚那样只是顺时针所要移动的距离,我们还要计算逆时针的到的结果,从顺时针和逆时针中找到最大的T,然后N-Max(T)才能够是正确结果.
    0
    回复 maxint64发表于2009-09-01 21:33
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    先是物理大发了——以为 b1,b2...bm是连续的
    看了牛们的题解 一次ac :)
    0
    回复 柔情使者发表于2009-08-20 15:44
    第一遍做的时候没有看题解,自己测了好几遍总是60分,看了n多大牛的解释才恍然大悟,竟然要正反两遍!!!唉,幸亏咱有测试数据,否则我可就惨了...
    O(n)的求目标队列算法,都说是冒泡排序,我没看出来,倒是有点像。
    0
    回复 maxiem发表于2009-08-18 20:55
    物理自重啊,嘿嘿。
    注意要正反两遍哦~
    9MS?
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 9ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:9ms
    (好像那个冒泡是口胡,大家不要被那个蒙了
    program fire;
    var
    st:array [1..50000,1..2] of longint;
    k,final:array [0..50000] of longint;
    ex:array [1..50000] of boolean;
    p,max,i,n:longint;
    begin
    fillchar (st,sizeof(st),0);
    fillchar (ex,sizeof(ex),0);
    fillchar (final,sizeof(final),0);
    fillchar (k,sizeof(k),0);
    readln (n);
    for i:=1 to n do readln (st,st);
    final[1]:=1;p:=2;ex[1]:=true;
    for i:=1 to n do begin
    if ex[st[final[i],1]]=false then begin
    final[p]:=st[final[i],1];
    ex[st[final[i],1]]:=true;
    inc(p);
    end
    else if ex[st[final[i],2]]=false then begin
    final[p]:=st[final[i],2];
    ex[st[final[i],2]]:=true;
    inc(p);
    end;
    end;
    if p-1<>n then begin
    writeln (-1);
    halt;
    end;
    max:=0;
    for i:=1 to n do if final[i]>=i then inc(k[final[i]-i]) else inc(k[n-i+final[i]]);
    for i:=0 to n-1 do if k[i]>max then max:=k[i];
    fillchar (k,sizeof(k),0);
    for i:=n downto 1 do if final[i]>=n-i+1 then inc(k[final[i]-n+i-1]) else inc(k[final[i]+i-1]);
    for i:=0 to n -1 do if k[i]>max then max:=k[i];
    writeln (n-max);
    end.
    0
    回复 suning发表于2009-08-14 09:43
    啊呜~
    一年前误解了题意~
    一年后理解了题意~
    然后就是1次美妙的AC
    PS:[误]解[理]解~~~[物理]?
    0
    回复 fengwuliu发表于2009-08-13 17:20
    lgxcgd说的太对了!太感谢了5555
    0
    回复 Matt发表于2009-08-11 22:28
    NOIP也会考高等数学...
    由于原图是环,所以置换群可表示为一次循环。作差是个好方法。
    但求冒泡排序是怎么作的
    0
    回复 3830372发表于2009-08-11 21:28
    Flag   Accepted
    题号   P1008
    类型(?)   模拟
    通过   1504人
    提交   4282次
    通过率   35%
    难度   3
    提交 讨论 题解 状态
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 尖端才子发表于2009-08-11 11:14
    纪念一下……第1500个AC……
    Flag    Accepted
    题号   P1008
    类型(?)   模拟
    通过   1500人
    提交   4274次
    通过率   35%
    难度   3
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 SecretAgent发表于2009-08-10 14:02
    置换群是正解
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 yangbei发表于2009-08-07 14:57
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 338ms
    ├ 测试数据 05:答案正确... 322ms
    ├ 测试数据 06:答案正确... 306ms
    ├ 测试数据 07:答案正确... 338ms
    ├ 测试数据 08:答案正确... 338ms
    ├ 测试数据 09:答案正确... 322ms
    ├ 测试数据 10:答案正确... 306ms
    Accepted 有效得分:100 有效耗时:2270ms
    算镜像时偷了点懒,不过也算一遍AC了
    0
    回复 ja_son发表于2009-08-06 15:44
    a:拆环成队,寻求目标队列。
    b:b1,b2...bm不是连续的,而且是任意的。只要有成立目标队列,与原来的队列相匹配就可以知道有多少(设为n个)需要移动位置,则代价就是n。
    c:目标队列有多种情况,可以反转,也可以左右移动。
    0
    回复 1s发表于2009-08-03 17:56
    如对本题有疑问可以参看我的题解:
    http://xujieqi.blog.hexun.com/35722312_d.html
    0
    回复 DMKaplony发表于2009-07-30 15:15
    当时的时间限制好像是2s。。有个题解说把1定为第一项然后进行冒泡排序。。不过这里是1s 啊。。。也行只有置换群了吧。
    0
    回复 xusc_2009发表于2009-07-28 14:30
    看不懂,只好搁浅
    什么时候想清楚了再做
    0
    回复 董发表于2009-07-24 19:11
    program p1008;
    var i,n,k,j,sum1,sum2,ans,max:longint;
       a,b,w,d,c:array[0..50005] of longint;
    begin
    readln(n);
    for i:=1 to n do
    readln(a[i],b[i]);
    w[1]:=1; w[2]:=a[w[1]];
    k:=1;
    repeat
    inc(k);
    if w[k-1]=a[w[k]] then w[k+1]:=b[w[k]]
      else if w[k-1]=b[w[k]] then w[k+1]:=a[w[k]]
       else begin
           writeln(-1);
           exit;
           end;
    until k=n;
    if w[n+1]<>w[1] then
           begin
           writeln(-1);
           exit;
           end;
    for i:=1 to n do
    begin
    a[i]:=w[i]-i;
    b[i]:=w[n-i+1]-i;
    if a[i]<0 then a[i]:=a[i]+n;
    if b[i]<0 then b[i]:=b[i]+n;
    inc(c[a[i]]);
    inc(d[b[i]]);
    end;
    for i:=0 to n-1 do
    begin
    if ans<c[i] then ans:=c[i];
    if ans<d[i] then ans:=d[i];
    end;
    writeln(n-ans);  
    end.
    0
    回复 我飞发表于2009-07-23 21:00
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 93狒狒发表于2009-07-23 20:59
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    秒杀......
    0
    回复 fjxmlhx发表于2009-07-22 13:15
    置换群,做2n次,顺时针和逆时针.
    对于一个置换,最小操作费用是所有循环长度的和.因此实际上是找出2n个置换中哪个置换循环长度为1的数量最多.
    0
    回复 340508965发表于2009-07-21 15:01
    ⊙﹏⊙b汗
    不知道的以为这是数学竞赛......
    ...
    我的数论与图论可以说脑袋里空白一片.........
    怎么办,我的竞赛啊
    ........
    算了 看了题解 大家写的
    总算弄懂这道题了
    先前以为b1,b2,b3..bm是连续的
    没想到是任意的!!!!!!!!!
    诶 叹悲歌未切 为撼奈何编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    总算AC了
    program p1008;
    var i,n,k,j,sum1,sum2,ans,max:longint;
    a,b,w,d,c:array[0..50005] of longint;
    begin
    readln(n);
    for i:=1 to n do
    readln(a[i],b[i]);
    w[1]:=1; w[2]:=a[w[1]];
    k:=1;
    repeat
    inc(k);
    if w[k-1]=a[w[k]] then w[k+1]:=b[w[k]]
    else if w[k-1]=b[w[k]] then w[k+1]:=a[w[k]]
    else begin
    writeln(-1);
    exit;
    end;
    until k=n;
    if w[n+1]<>w[1] then
    begin
    writeln(-1);
    exit;
    end;
    for i:=1 to n do
    begin
    a[i]:=w[i]-i;
    b[i]:=w[n-i+1]-i;
    if a[i]<0 then a[i]:=a[i]+n;
    if b[i]<0 then b[i]:=b[i]+n;
    inc(c[a[i]]);
    inc(d[b[i]]);
    end;
    for i:=0 to n-1 do
    begin
    if ans<c[i] then ans:=c[i];
    if ans<d[i] then ans:=d[i];
    end;
    writeln(n-ans);
    end.
    0
    回复 zsy90943发表于2009-07-18 00:51
    构造巧妙、、看来还是要学好数论和图论额、、、、
    0
    回复 POM无敌牛B发表于2009-07-16 11:47
    编译通过...
    ├ 测试数据 01:运行超时...
    ├ 测试数据 02:运行超时...
    ├ 测试数据 03:运行超时...
    ├ 测试数据 04:运行超时...
    ├ 测试数据 05:运行超时...
    ├ 测试数据 06:运行超时...
    ├ 测试数据 07:运行超时...
    ├ 测试数据 08:运行超时...
    ├ 测试数据 09:运行超时...
    ├ 测试数据 10:运行超时...
    Unaccepted 有效得分:0 有效耗时:0ms
    无奈 哪位哥哥救救我
    0
    回复 yxy发表于2009-06-16 18:16
    把置换解释成度为2图,真有才.
    求出序列,正反分别做一次差就行了.
    0
    回复 sxpeter发表于2009-06-14 16:56
    讲建环吧。数组w表示环,我用的是一种类似并查集的方法。
    begin
    read(n);
    for i:=1 to n do read(a[i],b[i]);
    t:=2;w[1]:=1;w[2]:=a[1];
    while true do begin
    if a[w[t]]<>w[t-1]then w[t+1]:=a[w[t]]//是否在左边
    else if b[w[t]]<>w[t-1]then w[t+1]:=b[w[t]]//是否在右边
    else begin writeln(-1);halt;end;//失败判断
    inc(t);
    if t>n then break;
    end;
    if w[n+1]<>w[1]then begin writeln(-1);halt;end;//本句一定要加!!!!!!
    end.
    0
    回复 lgxcgd发表于2009-05-17 20:24
    首先把这个圈看做一个图,每个同学看做一个顶点。因为要形成环,所以每个顶点的度必须为2。
    如果存在度数不为2的顶点,那么整个图无法构成一个环,即“无论怎么调整都不能符合每个同学的愿望”输出-1。
    如果是一个环,那么就遍历图,生成以第1个顶点为开头的序列。现在就要求出最小移动的代价。
    在理解题意所述的调整方式中,要注意实际上就是把M个在错误位置上的人移动到正确的位置上,代价为M。一次下令移动即可。
    假如生成的目标序列为1,5,3,2,4。我们现在就需要比较它和初始状态1,2,3,4,5,看有几个人离开了原来的位置。但这个序列实际代表的是一个环,而且方向正反有两种,就需要把初始序列正反分别转N次,和得到的序列比较,看其中最少有几个位置上的人编号不相同,就得到了我们要求的最小代价。
    上述方法有大量冗余。但可以发现转来转去不管怎么转,任意两个人之间的相对位置关系在这过程中都不会变。于是想到做差,如果差小于0则加上N。
    1 5 3 2 4
    - 1 2 3 4 5
    0 3 0 3 4
    这表示序列1,5,3,2,4不转动时1,3两个人在原来的位置上,转动3个位置后5和2两个人在原来的位置上,转动4个位置后只有4一个人会在原来的位置上。这就是说,1,5,3,2,4与1,2,3,4,5在旋转后最多有2个位置上的人编号相同,即最少有3个位置上的人编号不相同。同理要反转再求一次。
    记录每个不同的差值的个数,取其最大值P,即不调换次数最大的。结果N-P就是调换次数最小的。
    0
    回复 src250发表于2009-05-14 08:27
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    切记:重新构图时一定要对数组清空!我的第一次只有50分,就是这个原因!
    0
    回复 love19960108发表于2009-04-26 17:59
    这题可以用C++这样做么??
    include <iostream> include <cassert>
    using namespace std;
    long N,seq[50001],p=1;
    class{
    private:
    long nbr[50001][3];
    bool flag[50001];
    bool isnbr(long v1,long v2){
    for(int i=1;i<=nbr[v1][0];i++)
    if(nbr[v1][i]==v2) return true;
    return false;
    }
    public:
    bool AddE(long v1,long v2){
    if(isnbr(v1,v2)) return true;
    else if(nbr[v1][0]==2||nbr[v2][0]==2) return false;
    else{
    nbr[v1][++nbr[v1][0]]=v2;
    nbr[v2][++nbr[v2][0]]=v1;
    return true;
    }
    }
    void dfs(long i){
    assert(!flag[i]);
    flag[i]=true,seq[p++]=i;
    for(int j=1;j<=nbr[i][0];j++){
    if(!flag[nbr[i][j]]){
    dfs(nbr[i][j]);
    break;
    }
    }
    }
    }G;
    long solve(){
    long cnt1[50001]={0},cnt2[50001]={0},ans=0;
    for(int i=1,a,b;i<=N;i++){
    a=seq[i]-i;
    if(a<0) a+=N; b=seq[i]-(N+1-i); if(b<0) b+=N; if(++cnt1[a]>ans) ans=cnt1[a];
    if(++cnt2>ans) ans=cnt2;
    }
    return N-ans;
    }
    int main(){
    cin >> N;
    for(int i=1,nbr1,nbr2;i<=N;i++){
    cin >> nbr1 >> nbr2;
    if(!G.AddE(i,nbr1)||!G.AddE(i,nbr2)){
    cout << -1 << endl;
    return 0;
    }
    }
    G.dfs(1);
    cout << solve() << endl;
    return 0;
    }
    0
    回复 voyagec2发表于2009-03-18 15:53
    难理解,不过算法很精妙
    0
    回复 pRoevollove发表于2009-02-25 23:49
    天,把(p[i]-i+n)mod n理所当然地打成了abs(p[i]-i)
    结果一直50分……还一直以为自己构造错了……
    ps 我可以过楼下的范例哦
    0
    回复 ufo172849z发表于2009-01-24 23:05
    ms楼下的程序不能处理这种反例(测试数据还是不够强啊)
    6
    2 3
    1 3
    1 2
    5 6
    4 6
    4 5
    应该输出-1的吧?因为是两个环
    var a,b:array[0..50000]of longint;
    c:array[0..50000,1..2]of longint;
    d:array[0..50000]of boolean;
    i,j,k,m,n,max:longint;
    can:boolean;
    begin
    readln(n);
    for i:=1 to n do
    readln(c,c);
    b[0]:=c[1,1]; b[n]:=c[1,1];
    fillchar(d,sizeof(d),0);
    k:=1;
    can:=true;
    for i:=1 to n-1 do
    begin
    if d[k] then can:=false;
    b[i]:=k; d[k]:=true;
    if b=c[k,1] then k:=c[k,2]
    else if b=c[k,2] then k:=c[k,1]
    else can:=false;
    if not can then break;
    end;
    if can then
    if b[n]<>k then can:=false;
    if can then
    begin
    max:=-1;
    fillchar(a,sizeof(a),0);
    for i:=1 to n do
    inc(a[(b[i]-i+n) mod n]);
    for i:=0 to n-1 do
    if a[i]>max then max:=a[i];
    fillchar(a,sizeof(a),0);
    for i:=1 to n do
    inc(a[(b[n-i+1]-i+n)mod n]);
    for i:=1 to n-1 do
    if a[i]>max then max:=a[i];
    writeln(n-max);
    end
    else
    writeln(-1);
    end.
    0
    回复 tangdongjian发表于2009-01-23 22:17
    我在做镜像时把原先max直接覆盖上了,注意
    0
    回复 永恒888发表于2009-10-26 22:50
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 tangkunjie发表于2009-06-04 19:50
    挺烦人的题目
    0
    回复 ykspeter发表于2008-11-13 20:32
    program fire(input,output);
    var
    n,i,j,k,max,v:longint;
    a:array[0..100000,1..2] of longint;
    b,c:array[0..100000] of longint;
    begin
    readln(n);
    for i:=1 to n do readln(a,a);
    for i:=1 to n do
       begin
        k:=0;
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if (k=4) or (k=3)
        then begin
           writeln('-1');
           exit
           end
       end;
    b[1]:=1;i:=2;k:=a[1,1];j:=1;
    repeat
      b[i]:=k;
      inc(i);
      v:=k;
      if a[k,1]<>j
      then k:=a[k,1]
      else k:=a[k,2];
      j:=v;
    until i=n+1;
    fillchar(c,sizeof(c),0);
    for i:=1 to n do inc(c[(b[i]-i+n)mod n]);
    for i:=0 to n-1 do
       if c[i]>max
       then max:=c[i];
    fillchar(c,sizeof(c),0);max:=0;
    for i:=1 to n do inc(c[(b[n-i+1]-i+n)mod n]);
    for i:=n-1 downto 0 do
       if c[i]>max
       then max:=c[i];
    writeln(n-max);
    end.
    0
    回复 getuojian发表于2008-11-10 13:38
    include<stdio.h> include<memory.h>
    const int maxn=50010;
    int n;
    int f[maxn][2];
    int goal[maxn];
    int ans=maxn;
    int hash[maxn];
    bool SET_ORI(){
    bool flag[maxn];
    memset(flag, true, sizeof(flag));
    goal[1]=1; flag[1]=false;
    for (int i=1; i<=n-1; i++){
    if (flag[f[goal[i]][0]]){
    goal=f[goal[i]][0];
    flag[f[goal[i]][0]]=false;
    continue;
    }
    if (flag[f[goal[i]][1]]){
    goal=f[goal[i]][1];
    flag[f[goal[i]][1]]=false;
    continue;
    }
    return false;
    }
    if ((goal[n]!=f[1][0]) && (goal[n]!=f[1][1]))
    return false;
    return true;
    }
    int SWAP(int i, int j){
    int t=goal[i];
    goal[i]=goal[j];
    goal[j]=t;
    return 0;
    }
    int min(int i, int j){
    return i>j?j:i;
    }
    int HASH(){
    for(int i=1; i<=n; i++)
    hash[i]=goal[i]-i+n;
    return 0;
    }
    int CALC(){
    int temp[maxn2], back=0;
    memset(temp, 0, sizeof(temp));
    for (int i=1; i<=n; i++)
    temp[hash[i]%n]++;
    for (int i=1; i<=2n-1; i++)
    if (temp[i] > back)
    back=temp[i];
    return back;
    }
    int main(){
    freopen("fire.in", "r", stdin);
    freopen("fire.out", "w", stdout);
    scanf("%d", &n);
    for (int i=1; i<=n; i++)
    scanf("%d %d", &f[i][0], &f[i][1]);
    if (!SET_ORI()){
    printf("-1");
    return 0;
    }
    //forward
    HASH();
    ans=min(ans, n-CALC());
    //backward
    for (int i=1; i<=n/2; i++)
    SWAP(i,n-i+1);
    HASH();
    ans=min(ans, n-CALC());
    printf("%d", ans);
    return 0;
    }
    0
    回复 IVORY发表于2008-11-06 10:46
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    CHEAT的...
    0
    回复 storey p发表于2008-11-05 14:19
    回447389831:
    exit换成halt
    0
    回复 FenXy发表于2008-11-04 08:28
    艺术p245
    0
    回复 hlq发表于2008-11-01 14:31
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    求不在位置上的人数
    a【i】 第i位上的同学编号
    for i:=1 to n do
    begin
    inc(b[(a[i]-i+n) mod n])
    end;
    max:=0;
    for i:=0 to n-1 do
    if b[i]>max then max:=b[i];
    fillchar(b,sizeof(b),0);
    for i:=1 to n do
    begin
    inc(b[(a[i]-(n-i+1)+n)mod n]);//对称
    end;
    for i:=0 to n-1 do
    if b[i]>max then max:=b[i];
    0
    回复 Will~骷髅发表于2008-10-30 21:37
    编译通过...
    ├ 测试数据 01:运行超时...
    ├ 测试数据 02:运行超时...
    ├ 测试数据 03:运行时错误...|错误号: -1073741819
    ├ 测试数据 04:运行时错误...|错误号: -1073741819
    ├ 测试数据 05:运行时错误...|错误号: -1073741819
    ├ 测试数据 06:运行时错误...|错误号: -1073741819
    ├ 测试数据 07:运行时错误...|错误号: -1073741819
    ├ 测试数据 08:运行时错误...|错误号: -1073741819
    ├ 测试数据 09:运行时错误...|错误号: -1073741819
    ├ 测试数据 10:运行时错误...|错误号: -1073741819
    Unaccepted 有效得分:0 有效耗时:0ms
    怎么会这样???
    0
    回复 悲伤逆流成河发表于2008-10-28 22:13
    include <iostream> include <fstream>
    using namespace std ;
    int hash[50001];
    int n , i , j , t , maxs(0) ;
    inline void HASH ( int e[] )
    {
    for ( i = 1 ; i <= n ; i++ )
    {
    e[i] -= i ;
    if ( e[i] < 0 ) e[i] += n ;
    hash[e[i]]++ ;
    }
    for ( i = 0 ; i < 50001 ; i++ )
    if ( maxs < hash[i] ) maxs = hash[i] ;
    }
    int main(){
    ifstream fin ("fire.in") ;
    ofstream fout ("fire.out") ;
    fin >> n ;
    int e[n+1] , h[n+1][2] , e2[n+1];
    bool f[n+1] ;
    for ( i = 1 ; i <= n ; i++ )
    {
    f[i] = false ;
    fin >> h[i][0] >> h[i][1] ;
    }
    e[1] = 1 ;
    f[1] = true ;
    for ( i = 2 ; i <= n ; i++ )
    {
    if ( e < 0 ) { fout << -1 << endl ; exit(0) ; }
    if ( !f [ h[ e ][0] ] ) e[i] = h[ e ][0] ;
    if ( !f [ h[ e ][1] ] ) e[i] = h[ e ][1] ;
    f[ e[i] ] = true ;
    }
    for ( i = 1 , j = n ; i <= n ; i++,j-- ) e2[j] = e[i] ;
    HASH ( e ) ;
    memset ( hash , 0 , sizeof ( hash ) ) ;
    HASH ( e2 ) ;
    fout << n - maxs << endl ;
    }
    0
    回复 evelynhe发表于2008-10-26 16:31
    “置换群思想...今天刚明白...
    先构造新数列(要构造两次,否则只有70分),然后向右计算相对位置差,然后累加记录数组,然后用N减去相对位置差累加值最大的,就是答案... ”
    这是真的
    0
    回复 true1023发表于2008-10-25 09:32
    置换群的基本概念
    利用原序列和目标序列每个元素的绝对位置差来求出原序列每个元素对于目标序列的相对位置,找相对位置相同的最多的元素数,用总元素数减去它即为结果。
    0
    回复 447389831发表于2008-10-21 09:45
    program fire(input,output);
    var
    n,i,j,k,max,v:longint;
    a:array[0..100000,1..2] of longint;
    b,c:array[0..100000] of longint;
    begin
    readln(n);
    for i:=1 to n do readln(a,a);
    for i:=1 to n do
       begin
        k:=0;
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if (k=4) or (k=3)
        then begin
           writeln('-1');
           exit
           end
       end;
    b[1]:=1;i:=2;k:=a[1,1];j:=1;
    repeat
      b[i]:=k;
      inc(i);
      v:=k;
      if a[k,1]<>j
      then k:=a[k,1]
      else k:=a[k,2];
      j:=v;
    until i=n+1;
    fillchar(c,sizeof(c),0);
    for i:=1 to n do inc(c[(b[i]-i+n)mod n]);
    for i:=0 to n-1 do
       if c[i]>max
       then max:=c[i];
    fillchar(c,sizeof(c),0);max:=0;
    for i:=1 to n do inc(c[(b[n-i+1]-i+n)mod n]);
    for i:=n-1 downto 0 do
       if c[i]>max
       then max:=c[i];
    writeln(n-max);
    end.
    90 分,牛人门帮看下把
    0
    回复 cnfnje1发表于2008-10-17 18:12
    置换群.....是什么?
    readln(n);
    for i:=1 to n do readln(a[i],b[i]);
    c[1]:=1; c[2]:=a[1];
    for i:=3 to n do if c=a[c] then c[i]:=b[c]
    else if c=b[c] then c[i]:=a[c]
    else begin writeln(-1); halt end;
    if c[n]<>b[1] then begin writeln(-1); halt end;
    fillchar(d,sizeof(d),0);
    for i:=1 to n do inc(d[(c[i]-i+n)mod n]);
    for i:=0 to n-1 do if d[i]>m then m:=d[i];
    fillchar(d,sizeof(d),0);
    for i:=1 to n do inc(d[(c[i]+i-1)mod n]);
    for i:=0 to n-1 do if d[i]>m then m:=d[i];
    writeln(n-m);
    是么?
    0
    回复 lyrics发表于2008-10-12 19:55
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    技巧性比较强吧,楼下不必构造2次,计算时从头至尾算一次,再倒过来算一次就行了
    0
    回复 LV.唱响发表于2008-10-05 08:38
    置换群思想...今天刚明白...
    先构造新数列(要构造两次,否则只有70分),然后向右计算相对位置差,然后累加记录数组,然后用N减去相对位置差累加值最大的,就是答案...
    0
    回复 宇智波带波斯猫发表于2008-10-05 08:33
    Flag   Accepted
    题号   P1008
    类型(?)   其它
    通过   1065人
    提交   3000次
    通过率   35%
    难度   3
    第3000个提交的
    0
    回复 鸳鸯羡发表于2008-09-28 18:19
    include <iostream>
    using namespace std ;
    int hash[50001];
    int n , i , j , t , maxs(0) ;
    inline void HASH ( int e[] )
    {
    for ( i = 1 ; i <= n ; i++ )
    {
    e[i] -= i ;
    if ( e[i] < 0 ) e[i] += n ;
    hash[e[i]]++ ;
    }
    for ( i = 0 ; i < 50001 ; i++ )
    if ( maxs < hash[i] ) maxs = hash[i] ;
    }
    int main(){
    cin >> n ;
    int e[n+1] , h[n+1][2] , e2[n+1];
    bool f[n+1] ;
    for ( i = 1 ; i <= n ; i++ )
    {
    f[i] = false ;
    cin >> h[i][0] >> h[i][1] ;
    }
    e[1] = 1 ;
    f[1] = true ;
    for ( i = 2 ; i <= n ; i++ )
    {
    if ( e < 0 ) { cout << -1 << endl ; exit(0) ; }
    if ( !f [ h[ e ][0] ] ) e[i] = h[ e ][0] ;
    if ( !f [ h[ e ][1] ] ) e[i] = h[ e ][1] ;
    f[ e[i] ] = true ;
    }
    for ( i = 1 , j = n ; i <= n ; i++,j-- ) e2[j] = e[i] ;
    HASH ( e ) ;
    memset ( hash , 0 , sizeof ( hash ) ) ;
    HASH ( e2 ) ;
    cout << n - maxs << endl ;
    }
    80分
    0
    回复 月光疾风发表于2008-09-25 13:03
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    纪念我第200次提交!过第79题。。。。
    0
    回复 ghostplant发表于2008-09-20 19:48
    include <iostream> include <fstream> include <cassert>
    using namespace std;
    long N,seq[50001],p=1;
    class{
    private:
    long nbr[50001][3];
    bool flag[50001];
    bool isnbr(long v1,long v2){
    for(int i=1;i<=nbr[v1][0];i++)
    if(nbr[v1][i]==v2) return true;
    return false;
    }
    public:
    bool AddE(long v1,long v2){
    if(isnbr(v1,v2)) return true;
    else if(nbr[v1][0]==2||nbr[v2][0]==2) return false;
    else{
    nbr[v1][++nbr[v1][0]]=v2;
    nbr[v2][++nbr[v2][0]]=v1;
    return true;
    }
    }
    void dfs(long i){
    assert(!flag[i]);
    flag[i]=true,seq[p++]=i;
    for(int j=1;j<=nbr[i][0];j++){
    if(!flag[nbr[i][j]]){
    dfs(nbr[i][j]);
    break;
    }
    }
    }
    }G;
    long solve(void){
    long cnt1[50001]={0},cnt2[50001]={0},ans=0;
    for(int i=1,a,b;i<=N;i++){
    a=seq[i]-i;
    if(a<0) a+=N; b=seq[i]-(N+1-i); if(b<0) b+=N; if(++cnt1[a]>ans) ans=cnt1[a];
    if(++cnt2>ans) ans=cnt2;
    }
    return N-ans;
    }
    int main(){
    cin >> N;
    for(int i=1,nbr1,nbr2;i<=N;i++){
    cin >> nbr1 >> nbr2;
    if(!G.AddE(i,nbr1)||!G.AddE(i,nbr2)){
    cout << -1 << endl;
    return 0;
    }
    }
    G.dfs(1);
    cout << solve() << endl;
    return 0;
    }
    0
    回复 zzh19950802发表于2008-09-17 19:29
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案错误... ├ 标准行输出
     ├ 错误行输出
    ├ 测试数据 05:答案错误... ├ 标准行输出
     ├ 错误行输出
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 462ms
    ├ 测试数据 08:答案正确... 369ms
    ├ 测试数据 09:答案正确... 384ms
    ├ 测试数据 10:答案错误...程序输出比正确答案长
    为什么我的程序不对?
    include <iostream>
    using namespace std;
    define MAXN 50000
    int man[MAXN+2][2];
    int cercle[MAXN+2]={0,1};
    int used[MAXN+2]={0};
    int reduce[2][MAXN+2]={0};
    int n;
    int main()
    {
    long i,p,q=1,t;
    int max=0;
    cin>>n;
    for (i=1;i<=n;i++) cin>>man[i][0]>>man[i][1];
    p=man[q][1];
    for (i=2;i<=n+1;i++)
    {
    if (man[q][1]==p)
    {
    p=q;
    q=man[q][0];
    }
    else
    {
    if(man[q][0]!=p) break;
    p=q;
    q=man[q][1];
    }
    if(used[q]) break;
    else used[q]=1;
    cercle[i]=q;
    }
    if (i<=n+1) cout<<-1;
    else
    {
    for (i=1;i<=n;i++)
    {
    if((t=cercle[i]-i)<0) t+=n; reduce[0][t]++; if (reduce[0][t]>max) max=reduce[0][t];
    if ((t=cercle[i]-n+i-1)<0) t+=n; if (reduce[1][t]>max) max=reduce[1][t];
    }
    cout<<n-max;
    }
    return 0;
    }
    0
    回复 liaorc发表于2008-09-16 17:56
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 cxy450090074发表于2008-09-04 13:34
    oh no
    0
    回复 Lost.G发表于2008-08-22 15:49
    我在想``怎么样才能不看错这题呢
    0
    回复 bonism发表于2008-08-14 21:30
    时间复杂度O(N)。。。
    原来我一直把题意理解错。。。囧!!。。
    关于“置换群”,请看LRJ的《算法艺术与信息学竞赛》P245那一小节,还是比较好理解的。
    0
    回复 lemon_cn发表于2008-08-08 15:55
    热烈庆祝用pascal AC的第二题~
    p.s.我是C++的~~
    0
    回复 oipn4e2发表于2008-08-05 21:36
    解决效率不高,但AC了。
    0
    回复 notblack发表于2008-08-01 09:17
    用距离来分类,统计在原位的最大人数,奇怪的是
    b[1]:=1;
    b[2]:=a[1,1];
    b[n]:=a[1,2];
    建环的时候,上面的改成
    b[1]:=1;
    b[2]:=a[1,2];
    b[n]:=a[1,1];
    最后一个点却过不了,太奇怪了.
    0
    回复 332404521发表于2008-07-14 13:53
    对于初三刚刚中考完的我,要理解这题的意思是万万不能的。。。
    看题解我知道了应该怎么做,但那不是我的,所以不做了。。。
    哪天能证明出来那啥再来做
    0
    回复 Sheeta发表于2007-11-14 15:45
    好简单啊
    直接贪啊
    (P.S.置换群?什么东东...)
    0
    回复 mingyueyucai发表于2007-11-09 21:22
    我代码写了老长老长,结果还是只过了8个点,有没有搞错?
    我想请问一下,我和大家的一样,先排列出目标状态.然后确定初始状态时使得最多的人在目标位置上,然后交换.但是得到的答案总是偏大一点.
    然后我又把所有可以使最多的人在原位目标位置上的可能都尝试了一编(包括正反两个目标状态),结果还是只能过8个点,有2个点死都过不了!
    我的算法有什么问题吗?
    0
    回复 luanjiyang发表于2007-11-08 08:44
    很委琐的说 我提交了8遍。。
    0→0→10→10→10→10→70→AC
    -||
    0
    回复 lonelycorn发表于2007-11-05 23:31
    数论……好底歇的东西。
    0
    回复 gamejifan发表于2007-11-04 11:15
    这题的叙述,让我误会了一年多。tzkq……3q..要早知道是这种意思早就ac了这题。。显然没什么大意思,看过组合数学或者学过群论的都懂。。ms跟polya计数法那个循环的意思。。
    写的时候竟然因为交换的时候写错一个字母wa。我汗。
    0
    回复 Alexandria发表于2007-11-01 13:33
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    好强大的题啊,不看题解还真不会!
    0
    回复 clfhaha1234发表于2007-10-30 18:09
    请问什么是置换群啊?可以讲讲吗?………………
    0
    回复 rleepas发表于2007-10-30 13:18
    楼下都是正解?
    ......
    0
    回复 Ice_Msk发表于2007-10-18 20:35
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    什么是置换群?不知道。。。照样过。。。。
    0
    回复 junlonely发表于2007-10-18 20:13
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 江南不才发表于2007-10-11 16:19
    排序法这里会超时~
    比赛的时间是2S~~
    这里是1S~~
    (_)
    0
    回复 秒杀群众发表于2007-10-10 17:05
    居然是置换群。。。
    对了。。。什么是置换群...
    上网查啊!!!
    0
    回复 southstarj1发表于2007-10-02 18:50
    思想:
    置换群。(相关知识自己查)
    对于一组数据,按各人的意愿排出一个序列,
    如果无法排出,就输出-1。
    再将环状序列变成链状,则这个目标序列为一个置换群,
    与原序列(按1到n的一列)满足:
    交换的最少人数等于目标序列与原序列不重合的人数。
    因为总共有2n个目标序列(正反各n种),都算一遍就行了。
    步骤:
    读入数据;
    构造一个目标序列;
    统计该序列中元素位置与该元素在原序列位置的差值(同一方向)为i{i ∈ [0, n)}的元素个数;
    将该序列的反序统计一遍;
    从这些数据中选取一个最大的值max;
    输出n - max;
    注意:
    构造目标序列时判断能否构造的条件;
    统计一次差值的复杂度是O(n);
    统计差值的目的是求与原序列最多的重合人数;
    0
    回复 wangjin5发表于2007-09-19 22:38
    好经典的题奥
    确实有难度
    0
    回复 the_melody发表于2007-09-03 17:58
    Accepted 有效得分:100 有效耗时:0ms
    好经典的题奥
    0
    回复 richardxx发表于2007-08-22 17:36
    下面程序是错的,不好意思,弄错地方了....
    0
    回复 sm-star发表于2007-08-21 15:18
    题目所求就是每次进行连续交换的人数总和,这样,一个看似复杂的题目就变的异常的简单了!
    0
    回复 wasyyyy发表于2007-08-11 02:05
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    HOHO~~~看讨论的时候看到有人提到‘置换群’这个东西,突然想起来我刚买的一本组合数学上有这么一块东西,就拿过来看了。。。。
    然后就出现上面的东西了。。。。置换群,本来想求轮换的,发现轮换比较多,还是找不参与交换的比较好记。。。。
    优化的方法。。。我看了下好象不只一个人讲过了。。。而且似乎我跟他们的都一样(没仔细看)所以就不说了。。。效率是O(n)的。。不用建环。
    0
    回复 angieqiu发表于2007-08-10 22:49
    怎么判断建环失败啊?我的程序虽然AC但总觉得方法很傻
    0
    回复 梦ぁ逍遥发表于2007-07-17 13:45
    想到了用t[i]=b[i]-i表示环
    却没想到镜像..
    十分感谢visister
    让我从90分中挣扎出来...
    0
    回复 visister发表于2007-06-01 00:12
    首先明显地可以知道我们需要对于目标状态建立出一个环。如果无法建立这个环,那么结果一定是-1,当建立好环以后可以知道最小移动代价一定等于最少的不在目标位置上的人数。那么我们可以对目标环进行顺时针旋转1~n-1之中任意一个,答案就一定等于旋转中的不在自己位置上的人数最少的那样的环的状态。但是对于50000的数据,我们如果要将环旋转1~n-1次,那么总共加上判断不在自己位置上的人数时间复杂度为O(n^2),显然在限定时间内是无法出解的。因此我们进行逆向思维:不在自己位置上最少的人数就一定会等于总人数减去在自己位置上最多的人数(仔细想想),那么我们就将该问题转化为了求在自己的位置上最多的人数,这样一来,我们对初始目标环中每一个位置进行判断需要旋转多少次可以回到自己位置上,每一个人的选择都将映射到[0..n-1]的数组中,选取当中最大的情况就为所求,但是考虑到环可以反转,那么我们还需要将环再求一次镜像,就可以得到初始目标需要旋转多少次可以得到在自己位置上最多的人数的环的状态,最后通过总的人数减去它即为问题所求,时间复杂度为O(n);
    0
    回复 pyh119发表于2006-11-16 20:11
    哪个人不小心失火了找我啊!!!
    PS:我是安徽省芜湖市119接线员....
    0
    回复 maomingming发表于2006-11-06 18:40
    考虑旋转后最多可能重合的情况,另要注意圈可以反过来
    0
    回复 qian5发表于2006-09-30 21:35
    直接输出‘-1’有一个点过
    0
    回复 BambooLeaf发表于2006-09-26 18:17
    见过的最牛最简单的方法……
    将此题转换为冒泡排序,记录下所有交换的次数和两数间的距离,加上就行了……—__—|||
    具体是这样的,我们反向思维,本来是要求一个有序数列求出成为无序数列的代价,现在我们把无序数列(即目标数列)进行冒泡排序,然后……就是这样……
    看完之后,偶巨汗……
    0
    回复 xcjzj发表于2006-09-26 17:18
    每组数据确定两组相对位置关系,并且这两组互为镜像。
    对于某一种排列方式,不在需要位置上的人数即为当前状态到目标状态的最小代价。
    先找出其中一种排列方式。由于目标状态可以通过旋转而使得部分人的变化次数减少,所以找出每个人通过某一固定方向旋转到达目标位置的旋转次数。找到某一次数,使得拥有这个次数的人数最多。那么,通过旋转这一最多人拥有的次数,即可使得尽可能多的人不通过交换直接到达目标位置。于是,不拥有这一旋转次数的人数即为这一状态下的最小代价。
    然后,用现在的目标状态找出其镜像状态,并且用上述方法再找一遍最小代价,与前面的结果比较,较小值即为答案。
    另外,题目中会出现一些无解的情况:
    1.某个人被“要”的次数多于两次,也就是说有多于两个的人想要与他(她)邻座,那么无解。
    2.根据要求得出的目标状态为多于一个的环,也无解。
    0
    回复 东邪歪刀发表于2006-07-28 17:27
    提交了若干次……残念……
    0
    回复 sugar发表于2006-07-28 16:26
    这题比赛时真有人ac?
    真不好想
    为什么得开longint啊?
    0
    回复 晶星发表于2006-07-25 13:29
    排列本质不同的只有二种 正着和反着的
    检验几个人不在位置上用数学方法:)模拟法超时的
    0
    回复 tzkq发表于2006-07-23 04:37
    注意别误解题意 b1,b2....bm并不指连续位置上的数
    0
    回复 Coldwings发表于2006-01-26 09:21
    可以用群论证明:如果有k个人不在自己的位置上,那么要且仅要k的代价,即可使这些人归位
    剩下的..很简单了吧...
    0
    回复 lemon_cn发表于2008-08-08 15:55
    热烈庆祝用pascal AC的第二题~
    p.s.我是C++的~~
    0
    回复 yingjiangyu发表于2015-02-15 21:55
    打‘Wrong!’有50分。。
    0
    回复 东大微雕发表于2015-02-07 15:20
    这道题真是太好了。奇妙无穷。
    include<iostream> include<string.h> include<stdio.h>
    using namespace std;
    int a[50005];
    int size;
    void go(){
    int i, j;
    int ans = 0;
    int dis[50005];
    memset(dis, 0, sizeof(dis));
    for (i = 1; i <= size; i++){
    int d = (a[i] - i + size) % size;
    dis[d]++;
    }
    for (i = 0; i < size; i++){
    if (ans < dis[i])
    ans = dis[i];
    }
    memset(dis, 0, sizeof(dis));
    for (i = 1; i <= size; i++){
    int d = (a[size+1-i]-i+size) % size;
    dis[d]++;
    }
    for (i = 0; i < size; i++){
    if (ans < dis[i])ans = dis[i];
    }
    cout << size-ans << endl;
    }
    int main(){
    freopen("in.txt", "r", stdin);
    int neibor[50005][2];
    int i;
    cin >> size;
    for (i = 1; i <= size; i++){
    scanf("%d%d",&neibor[i][0],& neibor[i][1]);
    }
    bool used[50005];
    memset(used, 0, sizeof(used));
    a[1] = 1;
    used[1] = true;
    for (i = 2; i <= size; i++){
    int last = a[i - 1];
    if (!used[neibor[last][0]]){
    a[i] = neibor[last][0];
    used[a[i]] = true;
    }
    else if (!used[neibor[last][1]]){
    a[i] = neibor[last][1];
    used[a[i]] = true;
    }
    else {
    cout << -1 << endl;
    return 0;
    }
    }
    if (neibor[1][0] != a[size] && neibor[1][1] != a[size]){
    cout << -1 << endl;
    return 0;
    }
    go();
    return 0;
    }
    0
    回复 3516发表于2014-07-30 08:59
    include<stdio.h>
    include<string.h>
    int data[50001][2],shi[50001],a[50001];
    int main()
    {
    int n,i,j,qian,hou; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d%d",&data[i][0],&data[i][1]); } a[1]=1;shi[a[1]]=1 for(i=2;i<=n;i++) { qian=data[a[i-1]][0]; hou=data[a[i-1]][1]; if(shi[qian]==0) { a[i]=qian; shi[qian]=1; } else if(shi[hou]==0) { a[i]=hou; shi[hou]=1; } else { printf("-1"); return 0; } } int temp=0,max=0; memset(shi,0,sizeof(shi)); for(i=1;i<=n;i++) { temp=(n+a[i]-i+1)%n; shi[temp]++; } for(i=0;i<n;i++) { if(max<shi[i]) { max=shi[i]; } } memset(shi,0,sizeof(shi)); for(i=1;i<=n;i++) { temp=(n+a[n-i+1]-i+1)%n; shi[temp]++;
    }
    for(i=0;i<n;i++)
    {
    if(max<shi[i])max=shi[i];
    }
    printf("%d",n-max);
    }
    0
    回复 S.Y.F发表于2013-08-31 14:04
    题解
    1111111129回复于2014-08-13 11:52
    orzorzorz
    0
    回复 S.Y.F发表于2013-07-29 16:55
    从10、到30、到100。。。。。。
    题解:http://blog.163.com/syf_light_feather/blog/static/223755067201362945326756/
    0
    回复 vcvycy发表于2013-06-30 00:56
    20 30 40 50 70 分都有~泪流满面.
    Accepted
    100
    772 2
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:55:05
    Wrong Answer
    70
    613 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:53:24
    Wrong Answer
    70
    686 2
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:45:35
    Wrong Answer
    70
    856 2
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:42:12
    Wrong Answer
    70
    803 2
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:37:26
    Wrong Answer
    70
    882 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:22:39
    Wrong Answer
    70
    1145 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:20:30
    Wrong Answer
    10
    733 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:11:30
    Wrong Answer
    50
    723 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:04:20
    Wrong Answer
    50
    781 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:55:49
    Wrong Answer
    40
    656 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:49:49
    Wrong Answer
    40
    758 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:44:00
    Time Exceeded
    30
    7160 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:38:22
    Time Exceeded
    20
    7135 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:35:08
    0
    回复 SEX丶Elope发表于2013-02-16 10:10
    点击查看程序源码+详细题解
    cuichen回复于2014-09-09 09:24
    怎么又是你??你有什么企图?骗访问量???垃圾!
    0
    回复 qyjubriskxp发表于2010-07-09 21:31
    再一次体会到c++流的悲剧,秒杀和3s原来只是输入方式的不同,杯具~~
    yuyilahanbao回复于2014-01-24 11:47
    从c转到c++第一次不AC(除去忘记把语言有c改为c++的)就是因为c++输入输出的问题
    从那次起,我的c++的输入都是用scanf和printf了
    因为
    保险
    安全
    我记不清cin是<<还是>>
    printf和scanf相对更灵活
    ....
    0
    回复 slm发表于2010-03-16 18:27
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    嘿嘿
    0
    回复 superyoi发表于2009-11-10 11:50
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    superyoi killed p1008 with a headshot by awp
    0
    回复 200853349发表于2009-11-10 10:49
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    当我看到众位神牛打出“置换群”三个字后,我在黑书百度GOOGLE维基百科逛了得有一个半小时多然后回来AC了。。。
    思路和strini神牛的基本一样。
    0
    回复 sinb发表于2009-11-09 13:02
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    其实很简单,不要想复杂了,先是想办法构成,然后用置换群的方法即可ac。
    0
    回复 香蕉派发表于2009-11-06 11:29
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    虽然不懂什么叫置换群,但是思路还是很清晰的。。
    0
    回复 赏金神侠PPF发表于2009-11-05 11:45
    一星星纪念~
    0
    回复 strini发表于2009-10-30 22:11
    根据群论原理,任何置换群都可以分解为若干个循环节。显然,这道题目就是冲着这点来的。因为如果某循环的长度为L,那么本题中只需要代价为L的操作。注意,这里的L!=1,这是因为只有一个人的循环节不需要任何代价的操作。到这里才只能拿三十分,因为圈是可以旋转的,常规方法需要O(n^2)才能解决。不妨这里以编号为1的人为基准,定义每个人到自己应该所在位置的距离。距离不超过n-1。可以通过最大值来寻找能在自己位置上的最多的人数(因为距离为x的人在旋转x次后转到自己的位置上),那么在比较好的情况下,可以优化到O(n)。
    TIME: 1H
    SUBMIT:
    1 70 Error: 发现希望相邻是不精确的,于是改了个搜索方向。(以为题目给定的是按照左右方向,白书说过不能“假定”!)。
    2 90 Error: 终于明白要取两个搜索方向的最大值。
    3 Accepted.
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 skykey发表于2009-10-29 17:58
    include<iostream>
    using namespace std;
    int n;
    int a[50001],b[50001],c[50001];
    int aim[50001];
    void G_MAP()
    {
    bool mark[50001]={false};
    int p=1,r=1;
    while(p<=n)
    {
    aim[p]=r;mark[r]=true;p++;
    if(!mark[a[r]])r=a[r];
    else if(!mark[b[r]])r=b[r];
    else if(p<=n){cout<<-1;exit(0);}
    }
    }
    int COMPULATE()
    {
    int max=0;
    int t;
    int record[2][50001];
    for(int i=1;i<=n;i++)record[0][i]=record[1][i]=0;
    for(int i=1;i<=n;i++)
    {
    if((t=aim[i]-i)<0)t+=n; record[0][t]++; if(record[0][t]>max)max=record[0][t];
    if((t=aim[i]-(n+1-i))<0)t+=n; record[1][t]++; if (record[1][t]>max)max=record[1][t];
    }
    return max;
    }
    int main()
    {
    cin>>n;
    for(int i=1;i<=n;i++)
    {scanf("%d%d",&a[i],&b[i]);c[a[i]]++;c[b[i]]++;}
    for(int i=1;i<=n;i++)if(c[i]!=2){cout<<-1;return 0;}
    G_MAP();
    int T=COMPULATE();
    cout<<n-T;
    }
    0
    回复 song19931218发表于2009-10-27 20:11
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    考虑两种情形(貌似这两种情形很像,但又真的不同,后来才想起,在化学的手性碳原子那部分遇到过类似情况。。。)
    然后就是运用置换群的知识
    0
    回复 Aries_C发表于2009-10-25 08:24
    正反两遍...两遍...<幽幽的声音飘远..>
    不然就是70分啊...
    不看题解的情况下竟然自己想到了...
    记得以前老师给我们做过这题的..细节什么的现在做又忘记了..唉..
    0
    回复 国防安全员001发表于2009-10-21 22:00
    Flag   Accepted
    题号   P1008
    类型(?)   模拟
    通过   1701人
    提交   4835次
    通过率   35%
    难度   3
    题目表述有问题。。
    0
    回复 liubosen发表于2009-10-21 21:50
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    yaaaayyayayyayayayayayayayayayayayayayayayyaayayayayayayyaayayayay
    var
    n,max,i:longint;
    a,b,c,d:array[0..50001] of longint;
    begin
    readln(n);
    for i:=1 to n do
    readln(a[i],b[i]);
    c[1]:=1;
    c[2]:=a[1];
    for i:=3 to n do
    if c=a[c] then c[i]:=b[c]
    else
    if c=b[c] then c[i]:=a[c]
    else begin
    writeln(-1);
    halt
    end;
    if c[n]<>b[1] then
    begin
    writeln(-1);
    halt
    end;
    fillchar(d,sizeof(d),0);
    for i:=1 to n do
    inc(d[(c[i]-i+n)mod n]);
    for i:=0 to n-1 do
    if d[i]>max then max:=d[i];
    fillchar(d,sizeof(d),0);
    for i:=1 to n do
    inc(d[(c[i]+i-1)mod n]);
    for i:=0 to n-1 do
    if d[i]>max then max:=d[i];
    writeln(n-max);
    end.
    0
    回复 lishunzhi发表于2009-10-21 00:11
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    置换群,但建环是重点
    0
    回复 zebra发表于2009-10-03 09:48
    include <iostream> include <cassert>
    using namespace std;
    long N,seq[50001],p=1;
    class
    {
    private:
    long nbr[50001][3];
    bool flag[50001];
    bool isnbr(long v1,long v2)
    {
    for(int i=1;i<=nbr[v1][0];i++)
    if(nbr[v1][i]==v2)
    return true;
    return false;
    }
    public:
    bool AddE(long v1,long v2)
    {
    if(isnbr(v1,v2))
    return true;
    else
    if(nbr[v1][0]==2||nbr[v2][0]==2)
    return false;
    else
    {
    nbr[v1][++nbr[v1][0]]=v2;
    nbr[v2][++nbr[v2][0]]=v1;
    return true;
    }
    }
    void dfs(long i)
    {
    assert(!flag[i]);
    flag[i]=true,seq[p++]=i;
    for(int j=1;j<=nbr[i][0];j++)
    {
    if(!flag[nbr[i][j]])
    {
    dfs(nbr[i][j]);
    break;
    }
    }
    }
    }G;
    long solve()
    {
    long cnt1[50001]={0},cnt2[50001]={0},ans=0;
    for(int i=1,a,b;i<=N;i++){
    a=seq[i]-i;
    if(a<0) a+=N; b=seq[i]-(N+1-i); if(b<0) b+=N; if(++cnt1[a]>ans) ans=cnt1[a];
    if(++cnt2>ans) ans=cnt2;
    }
    return N-ans;
    }
    int main()
    {
    cin >> N;
    for(int i=1,nbr1,nbr2;i<=N;i++)
    {
    cin >> nbr1 >> nbr2;
    if(!G.AddE(i,nbr1)||!G.AddE(i,nbr2))
    {
    cout << -1 << endl;
    return 0;
    }
    }
    G.dfs(1);
    cout << solve() << endl;
    system("pause");
    return 0;
    }
    0
    回复 -117-Join发表于2009-09-18 21:29
    哪位大牛帮忙看看我错哪里了
    它只得90分
    program fire;
    type
    arr=record
    l,r:longint;
    end;
    var
    num:array[1..50000]of longint;
    a:array[1..50000]of arr;
    b:array[1..50000]of longint;
    i,k,j,n:longint;
    begin
    readln(n);
    for i:=1 to n do
    readln(a[i].l,a[i].r);
    b[1]:=1;
    b[n]:=a[1].l;
    if a[b[n]].l=b[1]then b[n-1]:=a[b[n]].r
    else b[n-1]:=a[b[n]].l;
    i:=n-1;
    b[2]:=a[1].r;
    j:=2;
    while j<=i do
    begin
    if b<>a[b[i]].l then b:=a[b[i]].l
    else b:=a[b[i]].r;
    dec(i);
    if b[j-1]<>a[b[j]].r then b[j+1]:=a[b[j]].r
    else b[j+1]:=a[b[j]].l;
    inc(j);
    end;
    for i:=2 to n-1 do
    if(b<>a[b[i]].r)and(b<>a[b[i]].l)or(b<>a[b[i]].r)and(b<>a[b[i]].l)then
    begin
    write(-1);
    halt
    end;
    if(b[n]<>a[b[1]].l)and(b[n]<>a[b[1]].r)or(b[2]<>a[b[1]].l)and(b[2]<>a[b[1]].r)or(b[1]<>a[b[n]].l)and(b[1]<>a[b[n]].r)or(b[n-1]<>a[b[n]].l)and(b[n-1]<>a[b[n]].r)then
    begin
    write(-1);
    halt
    end;
    num[0]:=0;
    for i:=1 to n do
    begin
    a[b[i]].l:=i;
    num[i]:=0;
    end;
    for i:=1 to n do
    if a[i].l-i>=0 then inc(num[a[i].l-i])
    else inc(num[a[i].l-i+n]);
    j:=0;
    for i:=0 to n do
    if num[i]>j then j:=num[i];
    write(n-j);
    end.
    写的有点长
    0
    回复 fs302发表于2009-09-17 20:13
    分析:学一个好思想:正难则反!由顺序到乱序我们很难快速找到,但是我们知道如何从乱序变为顺序!解决本题利用了组合数学中置换群的思想。
    从第一个人处断开,将圆环的问题转化为序列的问题。如果可以,求出目标序列。求出目标序列复杂度O(n).
    求出目标序列右移0至n-1位置时,不需要移动的人数。将目标序列反转,再求出目标序列右移0至n-1位置时,不需要移动的人数。求不需要移动的人数最大等价于求需要移动的人数最小。复杂度O(n)。
    更详细的说:
    引进“相对有序”这个概念,当两个人满足C[j]-C[i]==j-i时,两个相对有序。
    题目要求最小的总代价,但是我们可以考虑倒过来想,要求最小的总代价亦即求最多有多少人不用移动,亦即相对有序。
    然后我们引进一个辅助变量T=C-I,{C-I>=0},T=C[i]-I+N,{C[i]-I<0},那么这个T[i]有什么意义呢?我们知道初始状态的编号是1-N,而目标状态是C[1]-C[N],那么C-I便是从目标状态到初始状态顺时针所要移动的距离,那么如果那么T值相等的两个同学则是相对有序的,亦即不用移动,我们只要找出最大的T然后N-Max(T)就是得到的结果,但是这样还不够,因为刚刚那样只是顺时针所要移动的距离,我们还要计算逆时针的到的结果,从顺时针和逆时针中找到最大的T,然后N-Max(T)才能够是正确结果.
    0
    回复 maxint64发表于2009-09-01 21:33
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    先是物理大发了——以为 b1,b2...bm是连续的
    看了牛们的题解 一次ac :)
    0
    回复 柔情使者发表于2009-08-20 15:44
    第一遍做的时候没有看题解,自己测了好几遍总是60分,看了n多大牛的解释才恍然大悟,竟然要正反两遍!!!唉,幸亏咱有测试数据,否则我可就惨了...
    O(n)的求目标队列算法,都说是冒泡排序,我没看出来,倒是有点像。
    0
    回复 maxiem发表于2009-08-18 20:55
    物理自重啊,嘿嘿。
    注意要正反两遍哦~
    9MS?
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 9ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:9ms
    (好像那个冒泡是口胡,大家不要被那个蒙了
    program fire;
    var
    st:array [1..50000,1..2] of longint;
    k,final:array [0..50000] of longint;
    ex:array [1..50000] of boolean;
    p,max,i,n:longint;
    begin
    fillchar (st,sizeof(st),0);
    fillchar (ex,sizeof(ex),0);
    fillchar (final,sizeof(final),0);
    fillchar (k,sizeof(k),0);
    readln (n);
    for i:=1 to n do readln (st,st);
    final[1]:=1;p:=2;ex[1]:=true;
    for i:=1 to n do begin
    if ex[st[final[i],1]]=false then begin
    final[p]:=st[final[i],1];
    ex[st[final[i],1]]:=true;
    inc(p);
    end
    else if ex[st[final[i],2]]=false then begin
    final[p]:=st[final[i],2];
    ex[st[final[i],2]]:=true;
    inc(p);
    end;
    end;
    if p-1<>n then begin
    writeln (-1);
    halt;
    end;
    max:=0;
    for i:=1 to n do if final[i]>=i then inc(k[final[i]-i]) else inc(k[n-i+final[i]]);
    for i:=0 to n-1 do if k[i]>max then max:=k[i];
    fillchar (k,sizeof(k),0);
    for i:=n downto 1 do if final[i]>=n-i+1 then inc(k[final[i]-n+i-1]) else inc(k[final[i]+i-1]);
    for i:=0 to n -1 do if k[i]>max then max:=k[i];
    writeln (n-max);
    end.
    0
    回复 suning发表于2009-08-14 09:43
    啊呜~
    一年前误解了题意~
    一年后理解了题意~
    然后就是1次美妙的AC
    PS:[误]解[理]解~~~[物理]?
    0
    回复 fengwuliu发表于2009-08-13 17:20
    lgxcgd说的太对了!太感谢了5555
    0
    回复 Matt发表于2009-08-11 22:28
    NOIP也会考高等数学...
    由于原图是环,所以置换群可表示为一次循环。作差是个好方法。
    但求冒泡排序是怎么作的
    0
    回复 3830372发表于2009-08-11 21:28
    Flag   Accepted
    题号   P1008
    类型(?)   模拟
    通过   1504人
    提交   4282次
    通过率   35%
    难度   3
    提交 讨论 题解 状态
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 尖端才子发表于2009-08-11 11:14
    纪念一下……第1500个AC……
    Flag    Accepted
    题号   P1008
    类型(?)   模拟
    通过   1500人
    提交   4274次
    通过率   35%
    难度   3
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 SecretAgent发表于2009-08-10 14:02
    置换群是正解
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 yangbei发表于2009-08-07 14:57
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 338ms
    ├ 测试数据 05:答案正确... 322ms
    ├ 测试数据 06:答案正确... 306ms
    ├ 测试数据 07:答案正确... 338ms
    ├ 测试数据 08:答案正确... 338ms
    ├ 测试数据 09:答案正确... 322ms
    ├ 测试数据 10:答案正确... 306ms
    Accepted 有效得分:100 有效耗时:2270ms
    算镜像时偷了点懒,不过也算一遍AC了
    0
    回复 ja_son发表于2009-08-06 15:44
    a:拆环成队,寻求目标队列。
    b:b1,b2...bm不是连续的,而且是任意的。只要有成立目标队列,与原来的队列相匹配就可以知道有多少(设为n个)需要移动位置,则代价就是n。
    c:目标队列有多种情况,可以反转,也可以左右移动。
    0
    回复 1s发表于2009-08-03 17:56
    如对本题有疑问可以参看我的题解:
    http://xujieqi.blog.hexun.com/35722312_d.html
    0
    回复 DMKaplony发表于2009-07-30 15:15
    当时的时间限制好像是2s。。有个题解说把1定为第一项然后进行冒泡排序。。不过这里是1s 啊。。。也行只有置换群了吧。
    0
    回复 xusc_2009发表于2009-07-28 14:30
    看不懂,只好搁浅
    什么时候想清楚了再做
    0
    回复 董发表于2009-07-24 19:11
    program p1008;
    var i,n,k,j,sum1,sum2,ans,max:longint;
       a,b,w,d,c:array[0..50005] of longint;
    begin
    readln(n);
    for i:=1 to n do
    readln(a[i],b[i]);
    w[1]:=1; w[2]:=a[w[1]];
    k:=1;
    repeat
    inc(k);
    if w[k-1]=a[w[k]] then w[k+1]:=b[w[k]]
      else if w[k-1]=b[w[k]] then w[k+1]:=a[w[k]]
       else begin
           writeln(-1);
           exit;
           end;
    until k=n;
    if w[n+1]<>w[1] then
           begin
           writeln(-1);
           exit;
           end;
    for i:=1 to n do
    begin
    a[i]:=w[i]-i;
    b[i]:=w[n-i+1]-i;
    if a[i]<0 then a[i]:=a[i]+n;
    if b[i]<0 then b[i]:=b[i]+n;
    inc(c[a[i]]);
    inc(d[b[i]]);
    end;
    for i:=0 to n-1 do
    begin
    if ans<c[i] then ans:=c[i];
    if ans<d[i] then ans:=d[i];
    end;
    writeln(n-ans);  
    end.
    0
    回复 我飞发表于2009-07-23 21:00
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 93狒狒发表于2009-07-23 20:59
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    秒杀......
    0
    回复 fjxmlhx发表于2009-07-22 13:15
    置换群,做2n次,顺时针和逆时针.
    对于一个置换,最小操作费用是所有循环长度的和.因此实际上是找出2n个置换中哪个置换循环长度为1的数量最多.
    0
    回复 340508965发表于2009-07-21 15:01
    ⊙﹏⊙b汗
    不知道的以为这是数学竞赛......
    ...
    我的数论与图论可以说脑袋里空白一片.........
    怎么办,我的竞赛啊
    ........
    算了 看了题解 大家写的
    总算弄懂这道题了
    先前以为b1,b2,b3..bm是连续的
    没想到是任意的!!!!!!!!!
    诶 叹悲歌未切 为撼奈何编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    总算AC了
    program p1008;
    var i,n,k,j,sum1,sum2,ans,max:longint;
    a,b,w,d,c:array[0..50005] of longint;
    begin
    readln(n);
    for i:=1 to n do
    readln(a[i],b[i]);
    w[1]:=1; w[2]:=a[w[1]];
    k:=1;
    repeat
    inc(k);
    if w[k-1]=a[w[k]] then w[k+1]:=b[w[k]]
    else if w[k-1]=b[w[k]] then w[k+1]:=a[w[k]]
    else begin
    writeln(-1);
    exit;
    end;
    until k=n;
    if w[n+1]<>w[1] then
    begin
    writeln(-1);
    exit;
    end;
    for i:=1 to n do
    begin
    a[i]:=w[i]-i;
    b[i]:=w[n-i+1]-i;
    if a[i]<0 then a[i]:=a[i]+n;
    if b[i]<0 then b[i]:=b[i]+n;
    inc(c[a[i]]);
    inc(d[b[i]]);
    end;
    for i:=0 to n-1 do
    begin
    if ans<c[i] then ans:=c[i];
    if ans<d[i] then ans:=d[i];
    end;
    writeln(n-ans);
    end.
    0
    回复 zsy90943发表于2009-07-18 00:51
    构造巧妙、、看来还是要学好数论和图论额、、、、
    0
    回复 POM无敌牛B发表于2009-07-16 11:47
    编译通过...
    ├ 测试数据 01:运行超时...
    ├ 测试数据 02:运行超时...
    ├ 测试数据 03:运行超时...
    ├ 测试数据 04:运行超时...
    ├ 测试数据 05:运行超时...
    ├ 测试数据 06:运行超时...
    ├ 测试数据 07:运行超时...
    ├ 测试数据 08:运行超时...
    ├ 测试数据 09:运行超时...
    ├ 测试数据 10:运行超时...
    Unaccepted 有效得分:0 有效耗时:0ms
    无奈 哪位哥哥救救我
    0
    回复 yxy发表于2009-06-16 18:16
    把置换解释成度为2图,真有才.
    求出序列,正反分别做一次差就行了.
    0
    回复 sxpeter发表于2009-06-14 16:56
    讲建环吧。数组w表示环,我用的是一种类似并查集的方法。
    begin
    read(n);
    for i:=1 to n do read(a[i],b[i]);
    t:=2;w[1]:=1;w[2]:=a[1];
    while true do begin
    if a[w[t]]<>w[t-1]then w[t+1]:=a[w[t]]//是否在左边
    else if b[w[t]]<>w[t-1]then w[t+1]:=b[w[t]]//是否在右边
    else begin writeln(-1);halt;end;//失败判断
    inc(t);
    if t>n then break;
    end;
    if w[n+1]<>w[1]then begin writeln(-1);halt;end;//本句一定要加!!!!!!
    end.
    0
    回复 lgxcgd发表于2009-05-17 20:24
    首先把这个圈看做一个图,每个同学看做一个顶点。因为要形成环,所以每个顶点的度必须为2。
    如果存在度数不为2的顶点,那么整个图无法构成一个环,即“无论怎么调整都不能符合每个同学的愿望”输出-1。
    如果是一个环,那么就遍历图,生成以第1个顶点为开头的序列。现在就要求出最小移动的代价。
    在理解题意所述的调整方式中,要注意实际上就是把M个在错误位置上的人移动到正确的位置上,代价为M。一次下令移动即可。
    假如生成的目标序列为1,5,3,2,4。我们现在就需要比较它和初始状态1,2,3,4,5,看有几个人离开了原来的位置。但这个序列实际代表的是一个环,而且方向正反有两种,就需要把初始序列正反分别转N次,和得到的序列比较,看其中最少有几个位置上的人编号不相同,就得到了我们要求的最小代价。
    上述方法有大量冗余。但可以发现转来转去不管怎么转,任意两个人之间的相对位置关系在这过程中都不会变。于是想到做差,如果差小于0则加上N。
    1 5 3 2 4
    - 1 2 3 4 5
    0 3 0 3 4
    这表示序列1,5,3,2,4不转动时1,3两个人在原来的位置上,转动3个位置后5和2两个人在原来的位置上,转动4个位置后只有4一个人会在原来的位置上。这就是说,1,5,3,2,4与1,2,3,4,5在旋转后最多有2个位置上的人编号相同,即最少有3个位置上的人编号不相同。同理要反转再求一次。
    记录每个不同的差值的个数,取其最大值P,即不调换次数最大的。结果N-P就是调换次数最小的。
    0
    回复 src250发表于2009-05-14 08:27
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    切记:重新构图时一定要对数组清空!我的第一次只有50分,就是这个原因!
    0
    回复 love19960108发表于2009-04-26 17:59
    这题可以用C++这样做么??
    include <iostream> include <cassert>
    using namespace std;
    long N,seq[50001],p=1;
    class{
    private:
    long nbr[50001][3];
    bool flag[50001];
    bool isnbr(long v1,long v2){
    for(int i=1;i<=nbr[v1][0];i++)
    if(nbr[v1][i]==v2) return true;
    return false;
    }
    public:
    bool AddE(long v1,long v2){
    if(isnbr(v1,v2)) return true;
    else if(nbr[v1][0]==2||nbr[v2][0]==2) return false;
    else{
    nbr[v1][++nbr[v1][0]]=v2;
    nbr[v2][++nbr[v2][0]]=v1;
    return true;
    }
    }
    void dfs(long i){
    assert(!flag[i]);
    flag[i]=true,seq[p++]=i;
    for(int j=1;j<=nbr[i][0];j++){
    if(!flag[nbr[i][j]]){
    dfs(nbr[i][j]);
    break;
    }
    }
    }
    }G;
    long solve(){
    long cnt1[50001]={0},cnt2[50001]={0},ans=0;
    for(int i=1,a,b;i<=N;i++){
    a=seq[i]-i;
    if(a<0) a+=N; b=seq[i]-(N+1-i); if(b<0) b+=N; if(++cnt1[a]>ans) ans=cnt1[a];
    if(++cnt2>ans) ans=cnt2;
    }
    return N-ans;
    }
    int main(){
    cin >> N;
    for(int i=1,nbr1,nbr2;i<=N;i++){
    cin >> nbr1 >> nbr2;
    if(!G.AddE(i,nbr1)||!G.AddE(i,nbr2)){
    cout << -1 << endl;
    return 0;
    }
    }
    G.dfs(1);
    cout << solve() << endl;
    return 0;
    }
    0
    回复 voyagec2发表于2009-03-18 15:53
    难理解,不过算法很精妙
    0
    回复 pRoevollove发表于2009-02-25 23:49
    天,把(p[i]-i+n)mod n理所当然地打成了abs(p[i]-i)
    结果一直50分……还一直以为自己构造错了……
    ps 我可以过楼下的范例哦
    0
    回复 ufo172849z发表于2009-01-24 23:05
    ms楼下的程序不能处理这种反例(测试数据还是不够强啊)
    6
    2 3
    1 3
    1 2
    5 6
    4 6
    4 5
    应该输出-1的吧?因为是两个环
    var a,b:array[0..50000]of longint;
    c:array[0..50000,1..2]of longint;
    d:array[0..50000]of boolean;
    i,j,k,m,n,max:longint;
    can:boolean;
    begin
    readln(n);
    for i:=1 to n do
    readln(c,c);
    b[0]:=c[1,1]; b[n]:=c[1,1];
    fillchar(d,sizeof(d),0);
    k:=1;
    can:=true;
    for i:=1 to n-1 do
    begin
    if d[k] then can:=false;
    b[i]:=k; d[k]:=true;
    if b=c[k,1] then k:=c[k,2]
    else if b=c[k,2] then k:=c[k,1]
    else can:=false;
    if not can then break;
    end;
    if can then
    if b[n]<>k then can:=false;
    if can then
    begin
    max:=-1;
    fillchar(a,sizeof(a),0);
    for i:=1 to n do
    inc(a[(b[i]-i+n) mod n]);
    for i:=0 to n-1 do
    if a[i]>max then max:=a[i];
    fillchar(a,sizeof(a),0);
    for i:=1 to n do
    inc(a[(b[n-i+1]-i+n)mod n]);
    for i:=1 to n-1 do
    if a[i]>max then max:=a[i];
    writeln(n-max);
    end
    else
    writeln(-1);
    end.
    0
    回复 tangdongjian发表于2009-01-23 22:17
    我在做镜像时把原先max直接覆盖上了,注意
    0
    回复 永恒888发表于2009-10-26 22:50
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 tangkunjie发表于2009-06-04 19:50
    挺烦人的题目
    0
    回复 ykspeter发表于2008-11-13 20:32
    program fire(input,output);
    var
    n,i,j,k,max,v:longint;
    a:array[0..100000,1..2] of longint;
    b,c:array[0..100000] of longint;
    begin
    readln(n);
    for i:=1 to n do readln(a,a);
    for i:=1 to n do
       begin
        k:=0;
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if (k=4) or (k=3)
        then begin
           writeln('-1');
           exit
           end
       end;
    b[1]:=1;i:=2;k:=a[1,1];j:=1;
    repeat
      b[i]:=k;
      inc(i);
      v:=k;
      if a[k,1]<>j
      then k:=a[k,1]
      else k:=a[k,2];
      j:=v;
    until i=n+1;
    fillchar(c,sizeof(c),0);
    for i:=1 to n do inc(c[(b[i]-i+n)mod n]);
    for i:=0 to n-1 do
       if c[i]>max
       then max:=c[i];
    fillchar(c,sizeof(c),0);max:=0;
    for i:=1 to n do inc(c[(b[n-i+1]-i+n)mod n]);
    for i:=n-1 downto 0 do
       if c[i]>max
       then max:=c[i];
    writeln(n-max);
    end.
    0
    回复 getuojian发表于2008-11-10 13:38
    include<stdio.h> include<memory.h>
    const int maxn=50010;
    int n;
    int f[maxn][2];
    int goal[maxn];
    int ans=maxn;
    int hash[maxn];
    bool SET_ORI(){
    bool flag[maxn];
    memset(flag, true, sizeof(flag));
    goal[1]=1; flag[1]=false;
    for (int i=1; i<=n-1; i++){
    if (flag[f[goal[i]][0]]){
    goal=f[goal[i]][0];
    flag[f[goal[i]][0]]=false;
    continue;
    }
    if (flag[f[goal[i]][1]]){
    goal=f[goal[i]][1];
    flag[f[goal[i]][1]]=false;
    continue;
    }
    return false;
    }
    if ((goal[n]!=f[1][0]) && (goal[n]!=f[1][1]))
    return false;
    return true;
    }
    int SWAP(int i, int j){
    int t=goal[i];
    goal[i]=goal[j];
    goal[j]=t;
    return 0;
    }
    int min(int i, int j){
    return i>j?j:i;
    }
    int HASH(){
    for(int i=1; i<=n; i++)
    hash[i]=goal[i]-i+n;
    return 0;
    }
    int CALC(){
    int temp[maxn2], back=0;
    memset(temp, 0, sizeof(temp));
    for (int i=1; i<=n; i++)
    temp[hash[i]%n]++;
    for (int i=1; i<=2n-1; i++)
    if (temp[i] > back)
    back=temp[i];
    return back;
    }
    int main(){
    freopen("fire.in", "r", stdin);
    freopen("fire.out", "w", stdout);
    scanf("%d", &n);
    for (int i=1; i<=n; i++)
    scanf("%d %d", &f[i][0], &f[i][1]);
    if (!SET_ORI()){
    printf("-1");
    return 0;
    }
    //forward
    HASH();
    ans=min(ans, n-CALC());
    //backward
    for (int i=1; i<=n/2; i++)
    SWAP(i,n-i+1);
    HASH();
    ans=min(ans, n-CALC());
    printf("%d", ans);
    return 0;
    }
    0
    回复 IVORY发表于2008-11-06 10:46
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    CHEAT的...
    0
    回复 storey p发表于2008-11-05 14:19
    回447389831:
    exit换成halt
    0
    回复 FenXy发表于2008-11-04 08:28
    艺术p245
    0
    回复 hlq发表于2008-11-01 14:31
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    求不在位置上的人数
    a【i】 第i位上的同学编号
    for i:=1 to n do
    begin
    inc(b[(a[i]-i+n) mod n])
    end;
    max:=0;
    for i:=0 to n-1 do
    if b[i]>max then max:=b[i];
    fillchar(b,sizeof(b),0);
    for i:=1 to n do
    begin
    inc(b[(a[i]-(n-i+1)+n)mod n]);//对称
    end;
    for i:=0 to n-1 do
    if b[i]>max then max:=b[i];
    0
    回复 Will~骷髅发表于2008-10-30 21:37
    编译通过...
    ├ 测试数据 01:运行超时...
    ├ 测试数据 02:运行超时...
    ├ 测试数据 03:运行时错误...|错误号: -1073741819
    ├ 测试数据 04:运行时错误...|错误号: -1073741819
    ├ 测试数据 05:运行时错误...|错误号: -1073741819
    ├ 测试数据 06:运行时错误...|错误号: -1073741819
    ├ 测试数据 07:运行时错误...|错误号: -1073741819
    ├ 测试数据 08:运行时错误...|错误号: -1073741819
    ├ 测试数据 09:运行时错误...|错误号: -1073741819
    ├ 测试数据 10:运行时错误...|错误号: -1073741819
    Unaccepted 有效得分:0 有效耗时:0ms
    怎么会这样???
    0
    回复 悲伤逆流成河发表于2008-10-28 22:13
    include <iostream> include <fstream>
    using namespace std ;
    int hash[50001];
    int n , i , j , t , maxs(0) ;
    inline void HASH ( int e[] )
    {
    for ( i = 1 ; i <= n ; i++ )
    {
    e[i] -= i ;
    if ( e[i] < 0 ) e[i] += n ;
    hash[e[i]]++ ;
    }
    for ( i = 0 ; i < 50001 ; i++ )
    if ( maxs < hash[i] ) maxs = hash[i] ;
    }
    int main(){
    ifstream fin ("fire.in") ;
    ofstream fout ("fire.out") ;
    fin >> n ;
    int e[n+1] , h[n+1][2] , e2[n+1];
    bool f[n+1] ;
    for ( i = 1 ; i <= n ; i++ )
    {
    f[i] = false ;
    fin >> h[i][0] >> h[i][1] ;
    }
    e[1] = 1 ;
    f[1] = true ;
    for ( i = 2 ; i <= n ; i++ )
    {
    if ( e < 0 ) { fout << -1 << endl ; exit(0) ; }
    if ( !f [ h[ e ][0] ] ) e[i] = h[ e ][0] ;
    if ( !f [ h[ e ][1] ] ) e[i] = h[ e ][1] ;
    f[ e[i] ] = true ;
    }
    for ( i = 1 , j = n ; i <= n ; i++,j-- ) e2[j] = e[i] ;
    HASH ( e ) ;
    memset ( hash , 0 , sizeof ( hash ) ) ;
    HASH ( e2 ) ;
    fout << n - maxs << endl ;
    }
    0
    回复 evelynhe发表于2008-10-26 16:31
    “置换群思想...今天刚明白...
    先构造新数列(要构造两次,否则只有70分),然后向右计算相对位置差,然后累加记录数组,然后用N减去相对位置差累加值最大的,就是答案... ”
    这是真的
    0
    回复 true1023发表于2008-10-25 09:32
    置换群的基本概念
    利用原序列和目标序列每个元素的绝对位置差来求出原序列每个元素对于目标序列的相对位置,找相对位置相同的最多的元素数,用总元素数减去它即为结果。
    0
    回复 447389831发表于2008-10-21 09:45
    program fire(input,output);
    var
    n,i,j,k,max,v:longint;
    a:array[0..100000,1..2] of longint;
    b,c:array[0..100000] of longint;
    begin
    readln(n);
    for i:=1 to n do readln(a,a);
    for i:=1 to n do
       begin
        k:=0;
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if (k=4) or (k=3)
        then begin
           writeln('-1');
           exit
           end
       end;
    b[1]:=1;i:=2;k:=a[1,1];j:=1;
    repeat
      b[i]:=k;
      inc(i);
      v:=k;
      if a[k,1]<>j
      then k:=a[k,1]
      else k:=a[k,2];
      j:=v;
    until i=n+1;
    fillchar(c,sizeof(c),0);
    for i:=1 to n do inc(c[(b[i]-i+n)mod n]);
    for i:=0 to n-1 do
       if c[i]>max
       then max:=c[i];
    fillchar(c,sizeof(c),0);max:=0;
    for i:=1 to n do inc(c[(b[n-i+1]-i+n)mod n]);
    for i:=n-1 downto 0 do
       if c[i]>max
       then max:=c[i];
    writeln(n-max);
    end.
    90 分,牛人门帮看下把
    0
    回复 cnfnje1发表于2008-10-17 18:12
    置换群.....是什么?
    readln(n);
    for i:=1 to n do readln(a[i],b[i]);
    c[1]:=1; c[2]:=a[1];
    for i:=3 to n do if c=a[c] then c[i]:=b[c]
    else if c=b[c] then c[i]:=a[c]
    else begin writeln(-1); halt end;
    if c[n]<>b[1] then begin writeln(-1); halt end;
    fillchar(d,sizeof(d),0);
    for i:=1 to n do inc(d[(c[i]-i+n)mod n]);
    for i:=0 to n-1 do if d[i]>m then m:=d[i];
    fillchar(d,sizeof(d),0);
    for i:=1 to n do inc(d[(c[i]+i-1)mod n]);
    for i:=0 to n-1 do if d[i]>m then m:=d[i];
    writeln(n-m);
    是么?
    0
    回复 lyrics发表于2008-10-12 19:55
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    技巧性比较强吧,楼下不必构造2次,计算时从头至尾算一次,再倒过来算一次就行了
    0
    回复 LV.唱响发表于2008-10-05 08:38
    置换群思想...今天刚明白...
    先构造新数列(要构造两次,否则只有70分),然后向右计算相对位置差,然后累加记录数组,然后用N减去相对位置差累加值最大的,就是答案...
    0
    回复 宇智波带波斯猫发表于2008-10-05 08:33
    Flag   Accepted
    题号   P1008
    类型(?)   其它
    通过   1065人
    提交   3000次
    通过率   35%
    难度   3
    第3000个提交的
    0
    回复 鸳鸯羡发表于2008-09-28 18:19
    include <iostream>
    using namespace std ;
    int hash[50001];
    int n , i , j , t , maxs(0) ;
    inline void HASH ( int e[] )
    {
    for ( i = 1 ; i <= n ; i++ )
    {
    e[i] -= i ;
    if ( e[i] < 0 ) e[i] += n ;
    hash[e[i]]++ ;
    }
    for ( i = 0 ; i < 50001 ; i++ )
    if ( maxs < hash[i] ) maxs = hash[i] ;
    }
    int main(){
    cin >> n ;
    int e[n+1] , h[n+1][2] , e2[n+1];
    bool f[n+1] ;
    for ( i = 1 ; i <= n ; i++ )
    {
    f[i] = false ;
    cin >> h[i][0] >> h[i][1] ;
    }
    e[1] = 1 ;
    f[1] = true ;
    for ( i = 2 ; i <= n ; i++ )
    {
    if ( e < 0 ) { cout << -1 << endl ; exit(0) ; }
    if ( !f [ h[ e ][0] ] ) e[i] = h[ e ][0] ;
    if ( !f [ h[ e ][1] ] ) e[i] = h[ e ][1] ;
    f[ e[i] ] = true ;
    }
    for ( i = 1 , j = n ; i <= n ; i++,j-- ) e2[j] = e[i] ;
    HASH ( e ) ;
    memset ( hash , 0 , sizeof ( hash ) ) ;
    HASH ( e2 ) ;
    cout << n - maxs << endl ;
    }
    80分
    0
    回复 月光疾风发表于2008-09-25 13:03
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    纪念我第200次提交!过第79题。。。。
    0
    回复 ghostplant发表于2008-09-20 19:48
    include <iostream> include <fstream> include <cassert>
    using namespace std;
    long N,seq[50001],p=1;
    class{
    private:
    long nbr[50001][3];
    bool flag[50001];
    bool isnbr(long v1,long v2){
    for(int i=1;i<=nbr[v1][0];i++)
    if(nbr[v1][i]==v2) return true;
    return false;
    }
    public:
    bool AddE(long v1,long v2){
    if(isnbr(v1,v2)) return true;
    else if(nbr[v1][0]==2||nbr[v2][0]==2) return false;
    else{
    nbr[v1][++nbr[v1][0]]=v2;
    nbr[v2][++nbr[v2][0]]=v1;
    return true;
    }
    }
    void dfs(long i){
    assert(!flag[i]);
    flag[i]=true,seq[p++]=i;
    for(int j=1;j<=nbr[i][0];j++){
    if(!flag[nbr[i][j]]){
    dfs(nbr[i][j]);
    break;
    }
    }
    }
    }G;
    long solve(void){
    long cnt1[50001]={0},cnt2[50001]={0},ans=0;
    for(int i=1,a,b;i<=N;i++){
    a=seq[i]-i;
    if(a<0) a+=N; b=seq[i]-(N+1-i); if(b<0) b+=N; if(++cnt1[a]>ans) ans=cnt1[a];
    if(++cnt2>ans) ans=cnt2;
    }
    return N-ans;
    }
    int main(){
    cin >> N;
    for(int i=1,nbr1,nbr2;i<=N;i++){
    cin >> nbr1 >> nbr2;
    if(!G.AddE(i,nbr1)||!G.AddE(i,nbr2)){
    cout << -1 << endl;
    return 0;
    }
    }
    G.dfs(1);
    cout << solve() << endl;
    return 0;
    }
    0
    回复 zzh19950802发表于2008-09-17 19:29
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案错误... ├ 标准行输出
     ├ 错误行输出
    ├ 测试数据 05:答案错误... ├ 标准行输出
     ├ 错误行输出
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 462ms
    ├ 测试数据 08:答案正确... 369ms
    ├ 测试数据 09:答案正确... 384ms
    ├ 测试数据 10:答案错误...程序输出比正确答案长
    为什么我的程序不对?
    include <iostream>
    using namespace std;
    define MAXN 50000
    int man[MAXN+2][2];
    int cercle[MAXN+2]={0,1};
    int used[MAXN+2]={0};
    int reduce[2][MAXN+2]={0};
    int n;
    int main()
    {
    long i,p,q=1,t;
    int max=0;
    cin>>n;
    for (i=1;i<=n;i++) cin>>man[i][0]>>man[i][1];
    p=man[q][1];
    for (i=2;i<=n+1;i++)
    {
    if (man[q][1]==p)
    {
    p=q;
    q=man[q][0];
    }
    else
    {
    if(man[q][0]!=p) break;
    p=q;
    q=man[q][1];
    }
    if(used[q]) break;
    else used[q]=1;
    cercle[i]=q;
    }
    if (i<=n+1) cout<<-1;
    else
    {
    for (i=1;i<=n;i++)
    {
    if((t=cercle[i]-i)<0) t+=n; reduce[0][t]++; if (reduce[0][t]>max) max=reduce[0][t];
    if ((t=cercle[i]-n+i-1)<0) t+=n; if (reduce[1][t]>max) max=reduce[1][t];
    }
    cout<<n-max;
    }
    return 0;
    }
    0
    回复 liaorc发表于2008-09-16 17:56
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 cxy450090074发表于2008-09-04 13:34
    oh no
    0
    回复 Lost.G发表于2008-08-22 15:49
    我在想``怎么样才能不看错这题呢
    0
    回复 bonism发表于2008-08-14 21:30
    时间复杂度O(N)。。。
    原来我一直把题意理解错。。。囧!!。。
    关于“置换群”,请看LRJ的《算法艺术与信息学竞赛》P245那一小节,还是比较好理解的。
    0
    回复 lemon_cn发表于2008-08-08 15:55
    热烈庆祝用pascal AC的第二题~
    p.s.我是C++的~~
    0
    回复 oipn4e2发表于2008-08-05 21:36
    解决效率不高,但AC了。
    0
    回复 notblack发表于2008-08-01 09:17
    用距离来分类,统计在原位的最大人数,奇怪的是
    b[1]:=1;
    b[2]:=a[1,1];
    b[n]:=a[1,2];
    建环的时候,上面的改成
    b[1]:=1;
    b[2]:=a[1,2];
    b[n]:=a[1,1];
    最后一个点却过不了,太奇怪了.
    0
    回复 332404521发表于2008-07-14 13:53
    对于初三刚刚中考完的我,要理解这题的意思是万万不能的。。。
    看题解我知道了应该怎么做,但那不是我的,所以不做了。。。
    哪天能证明出来那啥再来做
    0
    回复 Sheeta发表于2007-11-14 15:45
    好简单啊
    直接贪啊
    (P.S.置换群?什么东东...)
    0
    回复 mingyueyucai发表于2007-11-09 21:22
    我代码写了老长老长,结果还是只过了8个点,有没有搞错?
    我想请问一下,我和大家的一样,先排列出目标状态.然后确定初始状态时使得最多的人在目标位置上,然后交换.但是得到的答案总是偏大一点.
    然后我又把所有可以使最多的人在原位目标位置上的可能都尝试了一编(包括正反两个目标状态),结果还是只能过8个点,有2个点死都过不了!
    我的算法有什么问题吗?
    0
    回复 luanjiyang发表于2007-11-08 08:44
    很委琐的说 我提交了8遍。。
    0→0→10→10→10→10→70→AC
    -||
    0
    回复 lonelycorn发表于2007-11-05 23:31
    数论……好底歇的东西。
    0
    回复 gamejifan发表于2007-11-04 11:15
    这题的叙述,让我误会了一年多。tzkq……3q..要早知道是这种意思早就ac了这题。。显然没什么大意思,看过组合数学或者学过群论的都懂。。ms跟polya计数法那个循环的意思。。
    写的时候竟然因为交换的时候写错一个字母wa。我汗。
    0
    回复 Alexandria发表于2007-11-01 13:33
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    好强大的题啊,不看题解还真不会!
    0
    回复 clfhaha1234发表于2007-10-30 18:09
    请问什么是置换群啊?可以讲讲吗?………………
    0
    回复 rleepas发表于2007-10-30 13:18
    楼下都是正解?
    ......
    0
    回复 Ice_Msk发表于2007-10-18 20:35
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    什么是置换群?不知道。。。照样过。。。。
    0
    回复 junlonely发表于2007-10-18 20:13
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 江南不才发表于2007-10-11 16:19
    排序法这里会超时~
    比赛的时间是2S~~
    这里是1S~~
    (_)
    0
    回复 秒杀群众发表于2007-10-10 17:05
    居然是置换群。。。
    对了。。。什么是置换群...
    上网查啊!!!
    0
    回复 southstarj1发表于2007-10-02 18:50
    思想:
    置换群。(相关知识自己查)
    对于一组数据,按各人的意愿排出一个序列,
    如果无法排出,就输出-1。
    再将环状序列变成链状,则这个目标序列为一个置换群,
    与原序列(按1到n的一列)满足:
    交换的最少人数等于目标序列与原序列不重合的人数。
    因为总共有2n个目标序列(正反各n种),都算一遍就行了。
    步骤:
    读入数据;
    构造一个目标序列;
    统计该序列中元素位置与该元素在原序列位置的差值(同一方向)为i{i ∈ [0, n)}的元素个数;
    将该序列的反序统计一遍;
    从这些数据中选取一个最大的值max;
    输出n - max;
    注意:
    构造目标序列时判断能否构造的条件;
    统计一次差值的复杂度是O(n);
    统计差值的目的是求与原序列最多的重合人数;
    0
    回复 wangjin5发表于2007-09-19 22:38
    好经典的题奥
    确实有难度
    0
    回复 the_melody发表于2007-09-03 17:58
    Accepted 有效得分:100 有效耗时:0ms
    好经典的题奥
    0
    回复 richardxx发表于2007-08-22 17:36
    下面程序是错的,不好意思,弄错地方了....
    0
    回复 sm-star发表于2007-08-21 15:18
    题目所求就是每次进行连续交换的人数总和,这样,一个看似复杂的题目就变的异常的简单了!
    0
    回复 wasyyyy发表于2007-08-11 02:05
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    HOHO~~~看讨论的时候看到有人提到‘置换群’这个东西,突然想起来我刚买的一本组合数学上有这么一块东西,就拿过来看了。。。。
    然后就出现上面的东西了。。。。置换群,本来想求轮换的,发现轮换比较多,还是找不参与交换的比较好记。。。。
    优化的方法。。。我看了下好象不只一个人讲过了。。。而且似乎我跟他们的都一样(没仔细看)所以就不说了。。。效率是O(n)的。。不用建环。
    0
    回复 angieqiu发表于2007-08-10 22:49
    怎么判断建环失败啊?我的程序虽然AC但总觉得方法很傻
    0
    回复 梦ぁ逍遥发表于2007-07-17 13:45
    想到了用t[i]=b[i]-i表示环
    却没想到镜像..
    十分感谢visister
    让我从90分中挣扎出来...
    0
    回复 visister发表于2007-06-01 00:12
    首先明显地可以知道我们需要对于目标状态建立出一个环。如果无法建立这个环,那么结果一定是-1,当建立好环以后可以知道最小移动代价一定等于最少的不在目标位置上的人数。那么我们可以对目标环进行顺时针旋转1~n-1之中任意一个,答案就一定等于旋转中的不在自己位置上的人数最少的那样的环的状态。但是对于50000的数据,我们如果要将环旋转1~n-1次,那么总共加上判断不在自己位置上的人数时间复杂度为O(n^2),显然在限定时间内是无法出解的。因此我们进行逆向思维:不在自己位置上最少的人数就一定会等于总人数减去在自己位置上最多的人数(仔细想想),那么我们就将该问题转化为了求在自己的位置上最多的人数,这样一来,我们对初始目标环中每一个位置进行判断需要旋转多少次可以回到自己位置上,每一个人的选择都将映射到[0..n-1]的数组中,选取当中最大的情况就为所求,但是考虑到环可以反转,那么我们还需要将环再求一次镜像,就可以得到初始目标需要旋转多少次可以得到在自己位置上最多的人数的环的状态,最后通过总的人数减去它即为问题所求,时间复杂度为O(n);
    0
    回复 pyh119发表于2006-11-16 20:11
    哪个人不小心失火了找我啊!!!
    PS:我是安徽省芜湖市119接线员....
    0
    回复 maomingming发表于2006-11-06 18:40
    考虑旋转后最多可能重合的情况,另要注意圈可以反过来
    0
    回复 qian5发表于2006-09-30 21:35
    直接输出‘-1’有一个点过
    0
    回复 BambooLeaf发表于2006-09-26 18:17
    见过的最牛最简单的方法……
    将此题转换为冒泡排序,记录下所有交换的次数和两数间的距离,加上就行了……—__—|||
    具体是这样的,我们反向思维,本来是要求一个有序数列求出成为无序数列的代价,现在我们把无序数列(即目标数列)进行冒泡排序,然后……就是这样……
    看完之后,偶巨汗……
    0
    回复 xcjzj发表于2006-09-26 17:18
    每组数据确定两组相对位置关系,并且这两组互为镜像。
    对于某一种排列方式,不在需要位置上的人数即为当前状态到目标状态的最小代价。
    先找出其中一种排列方式。由于目标状态可以通过旋转而使得部分人的变化次数减少,所以找出每个人通过某一固定方向旋转到达目标位置的旋转次数。找到某一次数,使得拥有这个次数的人数最多。那么,通过旋转这一最多人拥有的次数,即可使得尽可能多的人不通过交换直接到达目标位置。于是,不拥有这一旋转次数的人数即为这一状态下的最小代价。
    然后,用现在的目标状态找出其镜像状态,并且用上述方法再找一遍最小代价,与前面的结果比较,较小值即为答案。
    另外,题目中会出现一些无解的情况:
    1.某个人被“要”的次数多于两次,也就是说有多于两个的人想要与他(她)邻座,那么无解。
    2.根据要求得出的目标状态为多于一个的环,也无解。
    0
    回复 东邪歪刀发表于2006-07-28 17:27
    提交了若干次……残念……
    0
    回复 sugar发表于2006-07-28 16:26
    这题比赛时真有人ac?
    真不好想
    为什么得开longint啊?
    0
    回复 晶星发表于2006-07-25 13:29
    排列本质不同的只有二种 正着和反着的
    检验几个人不在位置上用数学方法:)模拟法超时的
    0
    回复 tzkq发表于2006-07-23 04:37
    注意别误解题意 b1,b2....bm并不指连续位置上的数
    0
    回复 Coldwings发表于2006-01-26 09:21
    可以用群论证明:如果有k个人不在自己的位置上,那么要且仅要k的代价,即可使这些人归位
    剩下的..很简单了吧...
    0
    回复 lemon_cn发表于2008-08-08 15:55
    热烈庆祝用pascal AC的第二题~
    p.s.我是C++的~~

    0

    回复 whxc049发表于2015-07-05 11:02
    0
    回复 yingjiangyu发表于2015-02-15 21:55
    打‘Wrong!’有50分。。
    0
    回复 东大微雕发表于2015-02-07 15:20
    这道题真是太好了。奇妙无穷。
    include<iostream> include<string.h> include<stdio.h>
    using namespace std;
    int a[50005];
    int size;
    void go(){
    int i, j;
    int ans = 0;
    int dis[50005];
    memset(dis, 0, sizeof(dis));
    for (i = 1; i <= size; i++){
    int d = (a[i] - i + size) % size;
    dis[d]++;
    }
    for (i = 0; i < size; i++){
    if (ans < dis[i])
    ans = dis[i];
    }
    memset(dis, 0, sizeof(dis));
    for (i = 1; i <= size; i++){
    int d = (a[size+1-i]-i+size) % size;
    dis[d]++;
    }
    for (i = 0; i < size; i++){
    if (ans < dis[i])ans = dis[i];
    }
    cout << size-ans << endl;
    }
    int main(){
    freopen("in.txt", "r", stdin);
    int neibor[50005][2];
    int i;
    cin >> size;
    for (i = 1; i <= size; i++){
    scanf("%d%d",&neibor[i][0],& neibor[i][1]);
    }
    bool used[50005];
    memset(used, 0, sizeof(used));
    a[1] = 1;
    used[1] = true;
    for (i = 2; i <= size; i++){
    int last = a[i - 1];
    if (!used[neibor[last][0]]){
    a[i] = neibor[last][0];
    used[a[i]] = true;
    }
    else if (!used[neibor[last][1]]){
    a[i] = neibor[last][1];
    used[a[i]] = true;
    }
    else {
    cout << -1 << endl;
    return 0;
    }
    }
    if (neibor[1][0] != a[size] && neibor[1][1] != a[size]){
    cout << -1 << endl;
    return 0;
    }
    go();
    return 0;
    }
    0
    回复 3516发表于2014-07-30 08:59
    include<stdio.h>
    include<string.h>
    int data[50001][2],shi[50001],a[50001];
    int main()
    {
    int n,i,j,qian,hou; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d%d",&data[i][0],&data[i][1]); } a[1]=1;shi[a[1]]=1 for(i=2;i<=n;i++) { qian=data[a[i-1]][0]; hou=data[a[i-1]][1]; if(shi[qian]==0) { a[i]=qian; shi[qian]=1; } else if(shi[hou]==0) { a[i]=hou; shi[hou]=1; } else { printf("-1"); return 0; } } int temp=0,max=0; memset(shi,0,sizeof(shi)); for(i=1;i<=n;i++) { temp=(n+a[i]-i+1)%n; shi[temp]++; } for(i=0;i<n;i++) { if(max<shi[i]) { max=shi[i]; } } memset(shi,0,sizeof(shi)); for(i=1;i<=n;i++) { temp=(n+a[n-i+1]-i+1)%n; shi[temp]++;
    }
    for(i=0;i<n;i++)
    {
    if(max<shi[i])max=shi[i];
    }
    printf("%d",n-max);
    }
    0
    回复 S.Y.F发表于2013-08-31 14:04
    题解
    1111111129回复于2014-08-13 11:52
    orzorzorz
    0
    回复 S.Y.F发表于2013-07-29 16:55
    从10、到30、到100。。。。。。
    题解:http://blog.163.com/syf_light_feather/blog/static/223755067201362945326756/
    0
    回复 vcvycy发表于2013-06-30 00:56
    20 30 40 50 70 分都有~泪流满面.
    Accepted
    100
    772 2
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:55:05
    Wrong Answer
    70
    613 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:53:24
    Wrong Answer
    70
    686 2
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:45:35
    Wrong Answer
    70
    856 2
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:42:12
    Wrong Answer
    70
    803 2
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:37:26
    Wrong Answer
    70
    882 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:22:39
    Wrong Answer
    70
    1145 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:20:30
    Wrong Answer
    10
    733 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:11:30
    Wrong Answer
    50
    723 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:04:20
    Wrong Answer
    50
    781 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:55:49
    Wrong Answer
    40
    656 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:49:49
    Wrong Answer
    40
    758 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:44:00
    Time Exceeded
    30
    7160 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:38:22
    Time Exceeded
    20
    7135 1
    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:35:08
    0
    回复 SEX丶Elope发表于2013-02-16 10:10
    点击查看程序源码+详细题解
    cuichen回复于2014-09-09 09:24
    怎么又是你??你有什么企图?骗访问量???垃圾!
    0
    回复 qyjubriskxp发表于2010-07-09 21:31
    再一次体会到c++流的悲剧,秒杀和3s原来只是输入方式的不同,杯具~~
    yuyilahanbao回复于2014-01-24 11:47
    从c转到c++第一次不AC(除去忘记把语言有c改为c++的)就是因为c++输入输出的问题
    从那次起,我的c++的输入都是用scanf和printf了
    因为
    保险
    安全
    我记不清cin是<<还是>>
    printf和scanf相对更灵活
    ....
    0
    回复 slm发表于2010-03-16 18:27
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    嘿嘿
    0
    回复 superyoi发表于2009-11-10 11:50
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    superyoi killed p1008 with a headshot by awp
    0
    回复 200853349发表于2009-11-10 10:49
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    当我看到众位神牛打出“置换群”三个字后,我在黑书百度GOOGLE维基百科逛了得有一个半小时多然后回来AC了。。。
    思路和strini神牛的基本一样。
    0
    回复 sinb发表于2009-11-09 13:02
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    其实很简单,不要想复杂了,先是想办法构成,然后用置换群的方法即可ac。
    0
    回复 香蕉派发表于2009-11-06 11:29
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    虽然不懂什么叫置换群,但是思路还是很清晰的。。
    0
    回复 赏金神侠PPF发表于2009-11-05 11:45
    一星星纪念~
    0
    回复 strini发表于2009-10-30 22:11
    根据群论原理,任何置换群都可以分解为若干个循环节。显然,这道题目就是冲着这点来的。因为如果某循环的长度为L,那么本题中只需要代价为L的操作。注意,这里的L!=1,这是因为只有一个人的循环节不需要任何代价的操作。到这里才只能拿三十分,因为圈是可以旋转的,常规方法需要O(n^2)才能解决。不妨这里以编号为1的人为基准,定义每个人到自己应该所在位置的距离。距离不超过n-1。可以通过最大值来寻找能在自己位置上的最多的人数(因为距离为x的人在旋转x次后转到自己的位置上),那么在比较好的情况下,可以优化到O(n)。
    TIME: 1H
    SUBMIT:
    1 70 Error: 发现希望相邻是不精确的,于是改了个搜索方向。(以为题目给定的是按照左右方向,白书说过不能“假定”!)。
    2 90 Error: 终于明白要取两个搜索方向的最大值。
    3 Accepted.
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 skykey发表于2009-10-29 17:58
    include<iostream>
    using namespace std;
    int n;
    int a[50001],b[50001],c[50001];
    int aim[50001];
    void G_MAP()
    {
    bool mark[50001]={false};
    int p=1,r=1;
    while(p<=n)
    {
    aim[p]=r;mark[r]=true;p++;
    if(!mark[a[r]])r=a[r];
    else if(!mark[b[r]])r=b[r];
    else if(p<=n){cout<<-1;exit(0);}
    }
    }
    int COMPULATE()
    {
    int max=0;
    int t;
    int record[2][50001];
    for(int i=1;i<=n;i++)record[0][i]=record[1][i]=0;
    for(int i=1;i<=n;i++)
    {
    if((t=aim[i]-i)<0)t+=n; record[0][t]++; if(record[0][t]>max)max=record[0][t];
    if((t=aim[i]-(n+1-i))<0)t+=n; record[1][t]++; if (record[1][t]>max)max=record[1][t];
    }
    return max;
    }
    int main()
    {
    cin>>n;
    for(int i=1;i<=n;i++)
    {scanf("%d%d",&a[i],&b[i]);c[a[i]]++;c[b[i]]++;}
    for(int i=1;i<=n;i++)if(c[i]!=2){cout<<-1;return 0;}
    G_MAP();
    int T=COMPULATE();
    cout<<n-T;
    }
    0
    回复 song19931218发表于2009-10-27 20:11
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    考虑两种情形(貌似这两种情形很像,但又真的不同,后来才想起,在化学的手性碳原子那部分遇到过类似情况。。。)
    然后就是运用置换群的知识
    0
    回复 Aries_C发表于2009-10-25 08:24
    正反两遍...两遍...<幽幽的声音飘远..>
    不然就是70分啊...
    不看题解的情况下竟然自己想到了...
    记得以前老师给我们做过这题的..细节什么的现在做又忘记了..唉..
    0
    回复 国防安全员001发表于2009-10-21 22:00
    Flag   Accepted
    题号   P1008
    类型(?)   模拟
    通过   1701人
    提交   4835次
    通过率   35%
    难度   3
    题目表述有问题。。
    0
    回复 liubosen发表于2009-10-21 21:50
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    yaaaayyayayyayayayayayayayayayayayayayayayyaayayayayayayyaayayayay
    var
    n,max,i:longint;
    a,b,c,d:array[0..50001] of longint;
    begin
    readln(n);
    for i:=1 to n do
    readln(a[i],b[i]);
    c[1]:=1;
    c[2]:=a[1];
    for i:=3 to n do
    if c=a[c] then c[i]:=b[c]
    else
    if c=b[c] then c[i]:=a[c]
    else begin
    writeln(-1);
    halt
    end;
    if c[n]<>b[1] then
    begin
    writeln(-1);
    halt
    end;
    fillchar(d,sizeof(d),0);
    for i:=1 to n do
    inc(d[(c[i]-i+n)mod n]);
    for i:=0 to n-1 do
    if d[i]>max then max:=d[i];
    fillchar(d,sizeof(d),0);
    for i:=1 to n do
    inc(d[(c[i]+i-1)mod n]);
    for i:=0 to n-1 do
    if d[i]>max then max:=d[i];
    writeln(n-max);
    end.
    0
    回复 lishunzhi发表于2009-10-21 00:11
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    置换群,但建环是重点
    0
    回复 zebra发表于2009-10-03 09:48
    include <iostream> include <cassert>
    using namespace std;
    long N,seq[50001],p=1;
    class
    {
    private:
    long nbr[50001][3];
    bool flag[50001];
    bool isnbr(long v1,long v2)
    {
    for(int i=1;i<=nbr[v1][0];i++)
    if(nbr[v1][i]==v2)
    return true;
    return false;
    }
    public:
    bool AddE(long v1,long v2)
    {
    if(isnbr(v1,v2))
    return true;
    else
    if(nbr[v1][0]==2||nbr[v2][0]==2)
    return false;
    else
    {
    nbr[v1][++nbr[v1][0]]=v2;
    nbr[v2][++nbr[v2][0]]=v1;
    return true;
    }
    }
    void dfs(long i)
    {
    assert(!flag[i]);
    flag[i]=true,seq[p++]=i;
    for(int j=1;j<=nbr[i][0];j++)
    {
    if(!flag[nbr[i][j]])
    {
    dfs(nbr[i][j]);
    break;
    }
    }
    }
    }G;
    long solve()
    {
    long cnt1[50001]={0},cnt2[50001]={0},ans=0;
    for(int i=1,a,b;i<=N;i++){
    a=seq[i]-i;
    if(a<0) a+=N; b=seq[i]-(N+1-i); if(b<0) b+=N; if(++cnt1[a]>ans) ans=cnt1[a];
    if(++cnt2>ans) ans=cnt2;
    }
    return N-ans;
    }
    int main()
    {
    cin >> N;
    for(int i=1,nbr1,nbr2;i<=N;i++)
    {
    cin >> nbr1 >> nbr2;
    if(!G.AddE(i,nbr1)||!G.AddE(i,nbr2))
    {
    cout << -1 << endl;
    return 0;
    }
    }
    G.dfs(1);
    cout << solve() << endl;
    system("pause");
    return 0;
    }
    0
    回复 -117-Join发表于2009-09-18 21:29
    哪位大牛帮忙看看我错哪里了
    它只得90分
    program fire;
    type
    arr=record
    l,r:longint;
    end;
    var
    num:array[1..50000]of longint;
    a:array[1..50000]of arr;
    b:array[1..50000]of longint;
    i,k,j,n:longint;
    begin
    readln(n);
    for i:=1 to n do
    readln(a[i].l,a[i].r);
    b[1]:=1;
    b[n]:=a[1].l;
    if a[b[n]].l=b[1]then b[n-1]:=a[b[n]].r
    else b[n-1]:=a[b[n]].l;
    i:=n-1;
    b[2]:=a[1].r;
    j:=2;
    while j<=i do
    begin
    if b<>a[b[i]].l then b:=a[b[i]].l
    else b:=a[b[i]].r;
    dec(i);
    if b[j-1]<>a[b[j]].r then b[j+1]:=a[b[j]].r
    else b[j+1]:=a[b[j]].l;
    inc(j);
    end;
    for i:=2 to n-1 do
    if(b<>a[b[i]].r)and(b<>a[b[i]].l)or(b<>a[b[i]].r)and(b<>a[b[i]].l)then
    begin
    write(-1);
    halt
    end;
    if(b[n]<>a[b[1]].l)and(b[n]<>a[b[1]].r)or(b[2]<>a[b[1]].l)and(b[2]<>a[b[1]].r)or(b[1]<>a[b[n]].l)and(b[1]<>a[b[n]].r)or(b[n-1]<>a[b[n]].l)and(b[n-1]<>a[b[n]].r)then
    begin
    write(-1);
    halt
    end;
    num[0]:=0;
    for i:=1 to n do
    begin
    a[b[i]].l:=i;
    num[i]:=0;
    end;
    for i:=1 to n do
    if a[i].l-i>=0 then inc(num[a[i].l-i])
    else inc(num[a[i].l-i+n]);
    j:=0;
    for i:=0 to n do
    if num[i]>j then j:=num[i];
    write(n-j);
    end.
    写的有点长
    0
    回复 fs302发表于2009-09-17 20:13
    分析:学一个好思想:正难则反!由顺序到乱序我们很难快速找到,但是我们知道如何从乱序变为顺序!解决本题利用了组合数学中置换群的思想。
    从第一个人处断开,将圆环的问题转化为序列的问题。如果可以,求出目标序列。求出目标序列复杂度O(n).
    求出目标序列右移0至n-1位置时,不需要移动的人数。将目标序列反转,再求出目标序列右移0至n-1位置时,不需要移动的人数。求不需要移动的人数最大等价于求需要移动的人数最小。复杂度O(n)。
    更详细的说:
    引进“相对有序”这个概念,当两个人满足C[j]-C[i]==j-i时,两个相对有序。
    题目要求最小的总代价,但是我们可以考虑倒过来想,要求最小的总代价亦即求最多有多少人不用移动,亦即相对有序。
    然后我们引进一个辅助变量T=C-I,{C-I>=0},T=C[i]-I+N,{C[i]-I<0},那么这个T[i]有什么意义呢?我们知道初始状态的编号是1-N,而目标状态是C[1]-C[N],那么C-I便是从目标状态到初始状态顺时针所要移动的距离,那么如果那么T值相等的两个同学则是相对有序的,亦即不用移动,我们只要找出最大的T然后N-Max(T)就是得到的结果,但是这样还不够,因为刚刚那样只是顺时针所要移动的距离,我们还要计算逆时针的到的结果,从顺时针和逆时针中找到最大的T,然后N-Max(T)才能够是正确结果.
    0
    回复 maxint64发表于2009-09-01 21:33
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    先是物理大发了——以为 b1,b2...bm是连续的
    看了牛们的题解 一次ac :)
    0
    回复 柔情使者发表于2009-08-20 15:44
    第一遍做的时候没有看题解,自己测了好几遍总是60分,看了n多大牛的解释才恍然大悟,竟然要正反两遍!!!唉,幸亏咱有测试数据,否则我可就惨了...
    O(n)的求目标队列算法,都说是冒泡排序,我没看出来,倒是有点像。
    0
    回复 maxiem发表于2009-08-18 20:55
    物理自重啊,嘿嘿。
    注意要正反两遍哦~
    9MS?
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 9ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:9ms
    (好像那个冒泡是口胡,大家不要被那个蒙了
    program fire;
    var
    st:array [1..50000,1..2] of longint;
    k,final:array [0..50000] of longint;
    ex:array [1..50000] of boolean;
    p,max,i,n:longint;
    begin
    fillchar (st,sizeof(st),0);
    fillchar (ex,sizeof(ex),0);
    fillchar (final,sizeof(final),0);
    fillchar (k,sizeof(k),0);
    readln (n);
    for i:=1 to n do readln (st,st);
    final[1]:=1;p:=2;ex[1]:=true;
    for i:=1 to n do begin
    if ex[st[final[i],1]]=false then begin
    final[p]:=st[final[i],1];
    ex[st[final[i],1]]:=true;
    inc(p);
    end
    else if ex[st[final[i],2]]=false then begin
    final[p]:=st[final[i],2];
    ex[st[final[i],2]]:=true;
    inc(p);
    end;
    end;
    if p-1<>n then begin
    writeln (-1);
    halt;
    end;
    max:=0;
    for i:=1 to n do if final[i]>=i then inc(k[final[i]-i]) else inc(k[n-i+final[i]]);
    for i:=0 to n-1 do if k[i]>max then max:=k[i];
    fillchar (k,sizeof(k),0);
    for i:=n downto 1 do if final[i]>=n-i+1 then inc(k[final[i]-n+i-1]) else inc(k[final[i]+i-1]);
    for i:=0 to n -1 do if k[i]>max then max:=k[i];
    writeln (n-max);
    end.
    0
    回复 suning发表于2009-08-14 09:43
    啊呜~
    一年前误解了题意~
    一年后理解了题意~
    然后就是1次美妙的AC
    PS:[误]解[理]解~~~[物理]?
    0
    回复 fengwuliu发表于2009-08-13 17:20
    lgxcgd说的太对了!太感谢了5555
    0
    回复 Matt发表于2009-08-11 22:28
    NOIP也会考高等数学...
    由于原图是环,所以置换群可表示为一次循环。作差是个好方法。
    但求冒泡排序是怎么作的
    0
    回复 3830372发表于2009-08-11 21:28
    Flag   Accepted
    题号   P1008
    类型(?)   模拟
    通过   1504人
    提交   4282次
    通过率   35%
    难度   3
    提交 讨论 题解 状态
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 尖端才子发表于2009-08-11 11:14
    纪念一下……第1500个AC……
    Flag    Accepted
    题号   P1008
    类型(?)   模拟
    通过   1500人
    提交   4274次
    通过率   35%
    难度   3
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 SecretAgent发表于2009-08-10 14:02
    置换群是正解
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 yangbei发表于2009-08-07 14:57
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 338ms
    ├ 测试数据 05:答案正确... 322ms
    ├ 测试数据 06:答案正确... 306ms
    ├ 测试数据 07:答案正确... 338ms
    ├ 测试数据 08:答案正确... 338ms
    ├ 测试数据 09:答案正确... 322ms
    ├ 测试数据 10:答案正确... 306ms
    Accepted 有效得分:100 有效耗时:2270ms
    算镜像时偷了点懒,不过也算一遍AC了
    0
    回复 ja_son发表于2009-08-06 15:44
    a:拆环成队,寻求目标队列。
    b:b1,b2...bm不是连续的,而且是任意的。只要有成立目标队列,与原来的队列相匹配就可以知道有多少(设为n个)需要移动位置,则代价就是n。
    c:目标队列有多种情况,可以反转,也可以左右移动。
    0
    回复 1s发表于2009-08-03 17:56
    如对本题有疑问可以参看我的题解:
    http://xujieqi.blog.hexun.com/35722312_d.html
    0
    回复 DMKaplony发表于2009-07-30 15:15
    当时的时间限制好像是2s。。有个题解说把1定为第一项然后进行冒泡排序。。不过这里是1s 啊。。。也行只有置换群了吧。
    0
    回复 xusc_2009发表于2009-07-28 14:30
    看不懂,只好搁浅
    什么时候想清楚了再做
    0
    回复 董发表于2009-07-24 19:11
    program p1008;
    var i,n,k,j,sum1,sum2,ans,max:longint;
       a,b,w,d,c:array[0..50005] of longint;
    begin
    readln(n);
    for i:=1 to n do
    readln(a[i],b[i]);
    w[1]:=1; w[2]:=a[w[1]];
    k:=1;
    repeat
    inc(k);
    if w[k-1]=a[w[k]] then w[k+1]:=b[w[k]]
      else if w[k-1]=b[w[k]] then w[k+1]:=a[w[k]]
       else begin
           writeln(-1);
           exit;
           end;
    until k=n;
    if w[n+1]<>w[1] then
           begin
           writeln(-1);
           exit;
           end;
    for i:=1 to n do
    begin
    a[i]:=w[i]-i;
    b[i]:=w[n-i+1]-i;
    if a[i]<0 then a[i]:=a[i]+n;
    if b[i]<0 then b[i]:=b[i]+n;
    inc(c[a[i]]);
    inc(d[b[i]]);
    end;
    for i:=0 to n-1 do
    begin
    if ans<c[i] then ans:=c[i];
    if ans<d[i] then ans:=d[i];
    end;
    writeln(n-ans);  
    end.
    0
    回复 我飞发表于2009-07-23 21:00
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 93狒狒发表于2009-07-23 20:59
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    秒杀......
    0
    回复 fjxmlhx发表于2009-07-22 13:15
    置换群,做2n次,顺时针和逆时针.
    对于一个置换,最小操作费用是所有循环长度的和.因此实际上是找出2n个置换中哪个置换循环长度为1的数量最多.
    0
    回复 340508965发表于2009-07-21 15:01
    ⊙﹏⊙b汗
    不知道的以为这是数学竞赛......
    ...
    我的数论与图论可以说脑袋里空白一片.........
    怎么办,我的竞赛啊
    ........
    算了 看了题解 大家写的
    总算弄懂这道题了
    先前以为b1,b2,b3..bm是连续的
    没想到是任意的!!!!!!!!!
    诶 叹悲歌未切 为撼奈何编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    总算AC了
    program p1008;
    var i,n,k,j,sum1,sum2,ans,max:longint;
    a,b,w,d,c:array[0..50005] of longint;
    begin
    readln(n);
    for i:=1 to n do
    readln(a[i],b[i]);
    w[1]:=1; w[2]:=a[w[1]];
    k:=1;
    repeat
    inc(k);
    if w[k-1]=a[w[k]] then w[k+1]:=b[w[k]]
    else if w[k-1]=b[w[k]] then w[k+1]:=a[w[k]]
    else begin
    writeln(-1);
    exit;
    end;
    until k=n;
    if w[n+1]<>w[1] then
    begin
    writeln(-1);
    exit;
    end;
    for i:=1 to n do
    begin
    a[i]:=w[i]-i;
    b[i]:=w[n-i+1]-i;
    if a[i]<0 then a[i]:=a[i]+n;
    if b[i]<0 then b[i]:=b[i]+n;
    inc(c[a[i]]);
    inc(d[b[i]]);
    end;
    for i:=0 to n-1 do
    begin
    if ans<c[i] then ans:=c[i];
    if ans<d[i] then ans:=d[i];
    end;
    writeln(n-ans);
    end.
    0
    回复 zsy90943发表于2009-07-18 00:51
    构造巧妙、、看来还是要学好数论和图论额、、、、
    0
    回复 POM无敌牛B发表于2009-07-16 11:47
    编译通过...
    ├ 测试数据 01:运行超时...
    ├ 测试数据 02:运行超时...
    ├ 测试数据 03:运行超时...
    ├ 测试数据 04:运行超时...
    ├ 测试数据 05:运行超时...
    ├ 测试数据 06:运行超时...
    ├ 测试数据 07:运行超时...
    ├ 测试数据 08:运行超时...
    ├ 测试数据 09:运行超时...
    ├ 测试数据 10:运行超时...
    Unaccepted 有效得分:0 有效耗时:0ms
    无奈 哪位哥哥救救我
    0
    回复 yxy发表于2009-06-16 18:16
    把置换解释成度为2图,真有才.
    求出序列,正反分别做一次差就行了.
    0
    回复 sxpeter发表于2009-06-14 16:56
    讲建环吧。数组w表示环,我用的是一种类似并查集的方法。
    begin
    read(n);
    for i:=1 to n do read(a[i],b[i]);
    t:=2;w[1]:=1;w[2]:=a[1];
    while true do begin
    if a[w[t]]<>w[t-1]then w[t+1]:=a[w[t]]//是否在左边
    else if b[w[t]]<>w[t-1]then w[t+1]:=b[w[t]]//是否在右边
    else begin writeln(-1);halt;end;//失败判断
    inc(t);
    if t>n then break;
    end;
    if w[n+1]<>w[1]then begin writeln(-1);halt;end;//本句一定要加!!!!!!
    end.
    0
    回复 lgxcgd发表于2009-05-17 20:24
    首先把这个圈看做一个图,每个同学看做一个顶点。因为要形成环,所以每个顶点的度必须为2。
    如果存在度数不为2的顶点,那么整个图无法构成一个环,即“无论怎么调整都不能符合每个同学的愿望”输出-1。
    如果是一个环,那么就遍历图,生成以第1个顶点为开头的序列。现在就要求出最小移动的代价。
    在理解题意所述的调整方式中,要注意实际上就是把M个在错误位置上的人移动到正确的位置上,代价为M。一次下令移动即可。
    假如生成的目标序列为1,5,3,2,4。我们现在就需要比较它和初始状态1,2,3,4,5,看有几个人离开了原来的位置。但这个序列实际代表的是一个环,而且方向正反有两种,就需要把初始序列正反分别转N次,和得到的序列比较,看其中最少有几个位置上的人编号不相同,就得到了我们要求的最小代价。
    上述方法有大量冗余。但可以发现转来转去不管怎么转,任意两个人之间的相对位置关系在这过程中都不会变。于是想到做差,如果差小于0则加上N。
    1 5 3 2 4
    - 1 2 3 4 5
    0 3 0 3 4
    这表示序列1,5,3,2,4不转动时1,3两个人在原来的位置上,转动3个位置后5和2两个人在原来的位置上,转动4个位置后只有4一个人会在原来的位置上。这就是说,1,5,3,2,4与1,2,3,4,5在旋转后最多有2个位置上的人编号相同,即最少有3个位置上的人编号不相同。同理要反转再求一次。
    记录每个不同的差值的个数,取其最大值P,即不调换次数最大的。结果N-P就是调换次数最小的。
    0
    回复 src250发表于2009-05-14 08:27
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    切记:重新构图时一定要对数组清空!我的第一次只有50分,就是这个原因!
    0
    回复 love19960108发表于2009-04-26 17:59
    这题可以用C++这样做么??
    include <iostream> include <cassert>
    using namespace std;
    long N,seq[50001],p=1;
    class{
    private:
    long nbr[50001][3];
    bool flag[50001];
    bool isnbr(long v1,long v2){
    for(int i=1;i<=nbr[v1][0];i++)
    if(nbr[v1][i]==v2) return true;
    return false;
    }
    public:
    bool AddE(long v1,long v2){
    if(isnbr(v1,v2)) return true;
    else if(nbr[v1][0]==2||nbr[v2][0]==2) return false;
    else{
    nbr[v1][++nbr[v1][0]]=v2;
    nbr[v2][++nbr[v2][0]]=v1;
    return true;
    }
    }
    void dfs(long i){
    assert(!flag[i]);
    flag[i]=true,seq[p++]=i;
    for(int j=1;j<=nbr[i][0];j++){
    if(!flag[nbr[i][j]]){
    dfs(nbr[i][j]);
    break;
    }
    }
    }
    }G;
    long solve(){
    long cnt1[50001]={0},cnt2[50001]={0},ans=0;
    for(int i=1,a,b;i<=N;i++){
    a=seq[i]-i;
    if(a<0) a+=N; b=seq[i]-(N+1-i); if(b<0) b+=N; if(++cnt1[a]>ans) ans=cnt1[a];
    if(++cnt2>ans) ans=cnt2;
    }
    return N-ans;
    }
    int main(){
    cin >> N;
    for(int i=1,nbr1,nbr2;i<=N;i++){
    cin >> nbr1 >> nbr2;
    if(!G.AddE(i,nbr1)||!G.AddE(i,nbr2)){
    cout << -1 << endl;
    return 0;
    }
    }
    G.dfs(1);
    cout << solve() << endl;
    return 0;
    }
    0
    回复 voyagec2发表于2009-03-18 15:53
    难理解,不过算法很精妙
    0
    回复 pRoevollove发表于2009-02-25 23:49
    天,把(p[i]-i+n)mod n理所当然地打成了abs(p[i]-i)
    结果一直50分……还一直以为自己构造错了……
    ps 我可以过楼下的范例哦
    0
    回复 ufo172849z发表于2009-01-24 23:05
    ms楼下的程序不能处理这种反例(测试数据还是不够强啊)
    6
    2 3
    1 3
    1 2
    5 6
    4 6
    4 5
    应该输出-1的吧?因为是两个环
    var a,b:array[0..50000]of longint;
    c:array[0..50000,1..2]of longint;
    d:array[0..50000]of boolean;
    i,j,k,m,n,max:longint;
    can:boolean;
    begin
    readln(n);
    for i:=1 to n do
    readln(c,c);
    b[0]:=c[1,1]; b[n]:=c[1,1];
    fillchar(d,sizeof(d),0);
    k:=1;
    can:=true;
    for i:=1 to n-1 do
    begin
    if d[k] then can:=false;
    b[i]:=k; d[k]:=true;
    if b=c[k,1] then k:=c[k,2]
    else if b=c[k,2] then k:=c[k,1]
    else can:=false;
    if not can then break;
    end;
    if can then
    if b[n]<>k then can:=false;
    if can then
    begin
    max:=-1;
    fillchar(a,sizeof(a),0);
    for i:=1 to n do
    inc(a[(b[i]-i+n) mod n]);
    for i:=0 to n-1 do
    if a[i]>max then max:=a[i];
    fillchar(a,sizeof(a),0);
    for i:=1 to n do
    inc(a[(b[n-i+1]-i+n)mod n]);
    for i:=1 to n-1 do
    if a[i]>max then max:=a[i];
    writeln(n-max);
    end
    else
    writeln(-1);
    end.
    0
    回复 tangdongjian发表于2009-01-23 22:17
    我在做镜像时把原先max直接覆盖上了,注意
    0
    回复 永恒888发表于2009-10-26 22:50
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 tangkunjie发表于2009-06-04 19:50
    挺烦人的题目
    0
    回复 ykspeter发表于2008-11-13 20:32
    program fire(input,output);
    var
    n,i,j,k,max,v:longint;
    a:array[0..100000,1..2] of longint;
    b,c:array[0..100000] of longint;
    begin
    readln(n);
    for i:=1 to n do readln(a,a);
    for i:=1 to n do
       begin
        k:=0;
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if (k=4) or (k=3)
        then begin
           writeln('-1');
           exit
           end
       end;
    b[1]:=1;i:=2;k:=a[1,1];j:=1;
    repeat
      b[i]:=k;
      inc(i);
      v:=k;
      if a[k,1]<>j
      then k:=a[k,1]
      else k:=a[k,2];
      j:=v;
    until i=n+1;
    fillchar(c,sizeof(c),0);
    for i:=1 to n do inc(c[(b[i]-i+n)mod n]);
    for i:=0 to n-1 do
       if c[i]>max
       then max:=c[i];
    fillchar(c,sizeof(c),0);max:=0;
    for i:=1 to n do inc(c[(b[n-i+1]-i+n)mod n]);
    for i:=n-1 downto 0 do
       if c[i]>max
       then max:=c[i];
    writeln(n-max);
    end.
    0
    回复 getuojian发表于2008-11-10 13:38
    include<stdio.h> include<memory.h>
    const int maxn=50010;
    int n;
    int f[maxn][2];
    int goal[maxn];
    int ans=maxn;
    int hash[maxn];
    bool SET_ORI(){
    bool flag[maxn];
    memset(flag, true, sizeof(flag));
    goal[1]=1; flag[1]=false;
    for (int i=1; i<=n-1; i++){
    if (flag[f[goal[i]][0]]){
    goal=f[goal[i]][0];
    flag[f[goal[i]][0]]=false;
    continue;
    }
    if (flag[f[goal[i]][1]]){
    goal=f[goal[i]][1];
    flag[f[goal[i]][1]]=false;
    continue;
    }
    return false;
    }
    if ((goal[n]!=f[1][0]) && (goal[n]!=f[1][1]))
    return false;
    return true;
    }
    int SWAP(int i, int j){
    int t=goal[i];
    goal[i]=goal[j];
    goal[j]=t;
    return 0;
    }
    int min(int i, int j){
    return i>j?j:i;
    }
    int HASH(){
    for(int i=1; i<=n; i++)
    hash[i]=goal[i]-i+n;
    return 0;
    }
    int CALC(){
    int temp[maxn2], back=0;
    memset(temp, 0, sizeof(temp));
    for (int i=1; i<=n; i++)
    temp[hash[i]%n]++;
    for (int i=1; i<=2n-1; i++)
    if (temp[i] > back)
    back=temp[i];
    return back;
    }
    int main(){
    freopen("fire.in", "r", stdin);
    freopen("fire.out", "w", stdout);
    scanf("%d", &n);
    for (int i=1; i<=n; i++)
    scanf("%d %d", &f[i][0], &f[i][1]);
    if (!SET_ORI()){
    printf("-1");
    return 0;
    }
    //forward
    HASH();
    ans=min(ans, n-CALC());
    //backward
    for (int i=1; i<=n/2; i++)
    SWAP(i,n-i+1);
    HASH();
    ans=min(ans, n-CALC());
    printf("%d", ans);
    return 0;
    }
    0
    回复 IVORY发表于2008-11-06 10:46
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    CHEAT的...
    0
    回复 storey p发表于2008-11-05 14:19
    回447389831:
    exit换成halt
    0
    回复 FenXy发表于2008-11-04 08:28
    艺术p245
    0
    回复 hlq发表于2008-11-01 14:31
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    求不在位置上的人数
    a【i】 第i位上的同学编号
    for i:=1 to n do
    begin
    inc(b[(a[i]-i+n) mod n])
    end;
    max:=0;
    for i:=0 to n-1 do
    if b[i]>max then max:=b[i];
    fillchar(b,sizeof(b),0);
    for i:=1 to n do
    begin
    inc(b[(a[i]-(n-i+1)+n)mod n]);//对称
    end;
    for i:=0 to n-1 do
    if b[i]>max then max:=b[i];
    0
    回复 Will~骷髅发表于2008-10-30 21:37
    编译通过...
    ├ 测试数据 01:运行超时...
    ├ 测试数据 02:运行超时...
    ├ 测试数据 03:运行时错误...|错误号: -1073741819
    ├ 测试数据 04:运行时错误...|错误号: -1073741819
    ├ 测试数据 05:运行时错误...|错误号: -1073741819
    ├ 测试数据 06:运行时错误...|错误号: -1073741819
    ├ 测试数据 07:运行时错误...|错误号: -1073741819
    ├ 测试数据 08:运行时错误...|错误号: -1073741819
    ├ 测试数据 09:运行时错误...|错误号: -1073741819
    ├ 测试数据 10:运行时错误...|错误号: -1073741819
    Unaccepted 有效得分:0 有效耗时:0ms
    怎么会这样???
    0
    回复 悲伤逆流成河发表于2008-10-28 22:13
    include <iostream> include <fstream>
    using namespace std ;
    int hash[50001];
    int n , i , j , t , maxs(0) ;
    inline void HASH ( int e[] )
    {
    for ( i = 1 ; i <= n ; i++ )
    {
    e[i] -= i ;
    if ( e[i] < 0 ) e[i] += n ;
    hash[e[i]]++ ;
    }
    for ( i = 0 ; i < 50001 ; i++ )
    if ( maxs < hash[i] ) maxs = hash[i] ;
    }
    int main(){
    ifstream fin ("fire.in") ;
    ofstream fout ("fire.out") ;
    fin >> n ;
    int e[n+1] , h[n+1][2] , e2[n+1];
    bool f[n+1] ;
    for ( i = 1 ; i <= n ; i++ )
    {
    f[i] = false ;
    fin >> h[i][0] >> h[i][1] ;
    }
    e[1] = 1 ;
    f[1] = true ;
    for ( i = 2 ; i <= n ; i++ )
    {
    if ( e < 0 ) { fout << -1 << endl ; exit(0) ; }
    if ( !f [ h[ e ][0] ] ) e[i] = h[ e ][0] ;
    if ( !f [ h[ e ][1] ] ) e[i] = h[ e ][1] ;
    f[ e[i] ] = true ;
    }
    for ( i = 1 , j = n ; i <= n ; i++,j-- ) e2[j] = e[i] ;
    HASH ( e ) ;
    memset ( hash , 0 , sizeof ( hash ) ) ;
    HASH ( e2 ) ;
    fout << n - maxs << endl ;
    }
    0
    回复 evelynhe发表于2008-10-26 16:31
    “置换群思想...今天刚明白...
    先构造新数列(要构造两次,否则只有70分),然后向右计算相对位置差,然后累加记录数组,然后用N减去相对位置差累加值最大的,就是答案... ”
    这是真的
    0
    回复 true1023发表于2008-10-25 09:32
    置换群的基本概念
    利用原序列和目标序列每个元素的绝对位置差来求出原序列每个元素对于目标序列的相对位置,找相对位置相同的最多的元素数,用总元素数减去它即为结果。
    0
    回复 447389831发表于2008-10-21 09:45
    program fire(input,output);
    var
    n,i,j,k,max,v:longint;
    a:array[0..100000,1..2] of longint;
    b,c:array[0..100000] of longint;
    begin
    readln(n);
    for i:=1 to n do readln(a,a);
    for i:=1 to n do
       begin
        k:=0;
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if (k=4) or (k=3)
        then begin
           writeln('-1');
           exit
           end
       end;
    b[1]:=1;i:=2;k:=a[1,1];j:=1;
    repeat
      b[i]:=k;
      inc(i);
      v:=k;
      if a[k,1]<>j
      then k:=a[k,1]
      else k:=a[k,2];
      j:=v;
    until i=n+1;
    fillchar(c,sizeof(c),0);
    for i:=1 to n do inc(c[(b[i]-i+n)mod n]);
    for i:=0 to n-1 do
       if c[i]>max
       then max:=c[i];
    fillchar(c,sizeof(c),0);max:=0;
    for i:=1 to n do inc(c[(b[n-i+1]-i+n)mod n]);
    for i:=n-1 downto 0 do
       if c[i]>max
       then max:=c[i];
    writeln(n-max);
    end.
    90 分,牛人门帮看下把
    0
    回复 cnfnje1发表于2008-10-17 18:12
    置换群.....是什么?
    readln(n);
    for i:=1 to n do readln(a[i],b[i]);
    c[1]:=1; c[2]:=a[1];
    for i:=3 to n do if c=a[c] then c[i]:=b[c]
    else if c=b[c] then c[i]:=a[c]
    else begin writeln(-1); halt end;
    if c[n]<>b[1] then begin writeln(-1); halt end;
    fillchar(d,sizeof(d),0);
    for i:=1 to n do inc(d[(c[i]-i+n)mod n]);
    for i:=0 to n-1 do if d[i]>m then m:=d[i];
    fillchar(d,sizeof(d),0);
    for i:=1 to n do inc(d[(c[i]+i-1)mod n]);
    for i:=0 to n-1 do if d[i]>m then m:=d[i];
    writeln(n-m);
    是么?
    0
    回复 lyrics发表于2008-10-12 19:55
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    技巧性比较强吧,楼下不必构造2次,计算时从头至尾算一次,再倒过来算一次就行了
    0
    回复 LV.唱响发表于2008-10-05 08:38
    置换群思想...今天刚明白...
    先构造新数列(要构造两次,否则只有70分),然后向右计算相对位置差,然后累加记录数组,然后用N减去相对位置差累加值最大的,就是答案...
    0
    回复 宇智波带波斯猫发表于2008-10-05 08:33
    Flag   Accepted
    题号   P1008
    类型(?)   其它
    通过   1065人
    提交   3000次
    通过率   35%
    难度   3
    第3000个提交的
    0
    回复 鸳鸯羡发表于2008-09-28 18:19
    include <iostream>
    using namespace std ;
    int hash[50001];
    int n , i , j , t , maxs(0) ;
    inline void HASH ( int e[] )
    {
    for ( i = 1 ; i <= n ; i++ )
    {
    e[i] -= i ;
    if ( e[i] < 0 ) e[i] += n ;
    hash[e[i]]++ ;
    }
    for ( i = 0 ; i < 50001 ; i++ )
    if ( maxs < hash[i] ) maxs = hash[i] ;
    }
    int main(){
    cin >> n ;
    int e[n+1] , h[n+1][2] , e2[n+1];
    bool f[n+1] ;
    for ( i = 1 ; i <= n ; i++ )
    {
    f[i] = false ;
    cin >> h[i][0] >> h[i][1] ;
    }
    e[1] = 1 ;
    f[1] = true ;
    for ( i = 2 ; i <= n ; i++ )
    {
    if ( e < 0 ) { cout << -1 << endl ; exit(0) ; }
    if ( !f [ h[ e ][0] ] ) e[i] = h[ e ][0] ;
    if ( !f [ h[ e ][1] ] ) e[i] = h[ e ][1] ;
    f[ e[i] ] = true ;
    }
    for ( i = 1 , j = n ; i <= n ; i++,j-- ) e2[j] = e[i] ;
    HASH ( e ) ;
    memset ( hash , 0 , sizeof ( hash ) ) ;
    HASH ( e2 ) ;
    cout << n - maxs << endl ;
    }
    80分
    0
    回复 月光疾风发表于2008-09-25 13:03
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    纪念我第200次提交!过第79题。。。。
    0
    回复 ghostplant发表于2008-09-20 19:48
    include <iostream> include <fstream> include <cassert>
    using namespace std;
    long N,seq[50001],p=1;
    class{
    private:
    long nbr[50001][3];
    bool flag[50001];
    bool isnbr(long v1,long v2){
    for(int i=1;i<=nbr[v1][0];i++)
    if(nbr[v1][i]==v2) return true;
    return false;
    }
    public:
    bool AddE(long v1,long v2){
    if(isnbr(v1,v2)) return true;
    else if(nbr[v1][0]==2||nbr[v2][0]==2) return false;
    else{
    nbr[v1][++nbr[v1][0]]=v2;
    nbr[v2][++nbr[v2][0]]=v1;
    return true;
    }
    }
    void dfs(long i){
    assert(!flag[i]);
    flag[i]=true,seq[p++]=i;
    for(int j=1;j<=nbr[i][0];j++){
    if(!flag[nbr[i][j]]){
    dfs(nbr[i][j]);
    break;
    }
    }
    }
    }G;
    long solve(void){
    long cnt1[50001]={0},cnt2[50001]={0},ans=0;
    for(int i=1,a,b;i<=N;i++){
    a=seq[i]-i;
    if(a<0) a+=N; b=seq[i]-(N+1-i); if(b<0) b+=N; if(++cnt1[a]>ans) ans=cnt1[a];
    if(++cnt2>ans) ans=cnt2;
    }
    return N-ans;
    }
    int main(){
    cin >> N;
    for(int i=1,nbr1,nbr2;i<=N;i++){
    cin >> nbr1 >> nbr2;
    if(!G.AddE(i,nbr1)||!G.AddE(i,nbr2)){
    cout << -1 << endl;
    return 0;
    }
    }
    G.dfs(1);
    cout << solve() << endl;
    return 0;
    }
    0
    回复 zzh19950802发表于2008-09-17 19:29
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案错误... ├ 标准行输出
     ├ 错误行输出
    ├ 测试数据 05:答案错误... ├ 标准行输出
     ├ 错误行输出
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 462ms
    ├ 测试数据 08:答案正确... 369ms
    ├ 测试数据 09:答案正确... 384ms
    ├ 测试数据 10:答案错误...程序输出比正确答案长
    为什么我的程序不对?
    include <iostream>
    using namespace std;
    define MAXN 50000
    int man[MAXN+2][2];
    int cercle[MAXN+2]={0,1};
    int used[MAXN+2]={0};
    int reduce[2][MAXN+2]={0};
    int n;
    int main()
    {
    long i,p,q=1,t;
    int max=0;
    cin>>n;
    for (i=1;i<=n;i++) cin>>man[i][0]>>man[i][1];
    p=man[q][1];
    for (i=2;i<=n+1;i++)
    {
    if (man[q][1]==p)
    {
    p=q;
    q=man[q][0];
    }
    else
    {
    if(man[q][0]!=p) break;
    p=q;
    q=man[q][1];
    }
    if(used[q]) break;
    else used[q]=1;
    cercle[i]=q;
    }
    if (i<=n+1) cout<<-1;
    else
    {
    for (i=1;i<=n;i++)
    {
    if((t=cercle[i]-i)<0) t+=n; reduce[0][t]++; if (reduce[0][t]>max) max=reduce[0][t];
    if ((t=cercle[i]-n+i-1)<0) t+=n; if (reduce[1][t]>max) max=reduce[1][t];
    }
    cout<<n-max;
    }
    return 0;
    }
    0
    回复 liaorc发表于2008-09-16 17:56
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 cxy450090074发表于2008-09-04 13:34
    oh no
    0
    回复 Lost.G发表于2008-08-22 15:49
    我在想``怎么样才能不看错这题呢
    0
    回复 bonism发表于2008-08-14 21:30
    时间复杂度O(N)。。。
    原来我一直把题意理解错。。。囧!!。。
    关于“置换群”,请看LRJ的《算法艺术与信息学竞赛》P245那一小节,还是比较好理解的。
    0
    回复 lemon_cn发表于2008-08-08 15:55
    热烈庆祝用pascal AC的第二题~
    p.s.我是C++的~~
    0
    回复 oipn4e2发表于2008-08-05 21:36
    解决效率不高,但AC了。
    0
    回复 notblack发表于2008-08-01 09:17
    用距离来分类,统计在原位的最大人数,奇怪的是
    b[1]:=1;
    b[2]:=a[1,1];
    b[n]:=a[1,2];
    建环的时候,上面的改成
    b[1]:=1;
    b[2]:=a[1,2];
    b[n]:=a[1,1];
    最后一个点却过不了,太奇怪了.
    0
    回复 332404521发表于2008-07-14 13:53
    对于初三刚刚中考完的我,要理解这题的意思是万万不能的。。。
    看题解我知道了应该怎么做,但那不是我的,所以不做了。。。
    哪天能证明出来那啥再来做
    0
    回复 Sheeta发表于2007-11-14 15:45
    好简单啊
    直接贪啊
    (P.S.置换群?什么东东...)
    0
    回复 mingyueyucai发表于2007-11-09 21:22
    我代码写了老长老长,结果还是只过了8个点,有没有搞错?
    我想请问一下,我和大家的一样,先排列出目标状态.然后确定初始状态时使得最多的人在目标位置上,然后交换.但是得到的答案总是偏大一点.
    然后我又把所有可以使最多的人在原位目标位置上的可能都尝试了一编(包括正反两个目标状态),结果还是只能过8个点,有2个点死都过不了!
    我的算法有什么问题吗?
    0
    回复 luanjiyang发表于2007-11-08 08:44
    很委琐的说 我提交了8遍。。
    0→0→10→10→10→10→70→AC
    -||
    0
    回复 lonelycorn发表于2007-11-05 23:31
    数论……好底歇的东西。
    0
    回复 gamejifan发表于2007-11-04 11:15
    这题的叙述,让我误会了一年多。tzkq……3q..要早知道是这种意思早就ac了这题。。显然没什么大意思,看过组合数学或者学过群论的都懂。。ms跟polya计数法那个循环的意思。。
    写的时候竟然因为交换的时候写错一个字母wa。我汗。
    0
    回复 Alexandria发表于2007-11-01 13:33
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    好强大的题啊,不看题解还真不会!
    0
    回复 clfhaha1234发表于2007-10-30 18:09
    请问什么是置换群啊?可以讲讲吗?………………
    0
    回复 rleepas发表于2007-10-30 13:18
    楼下都是正解?
    ......
    0
    回复 Ice_Msk发表于2007-10-18 20:35
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    什么是置换群?不知道。。。照样过。。。。
    0
    回复 junlonely发表于2007-10-18 20:13
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    0
    回复 江南不才发表于2007-10-11 16:19
    排序法这里会超时~
    比赛的时间是2S~~
    这里是1S~~
    (_)
    0
    回复 秒杀群众发表于2007-10-10 17:05
    居然是置换群。。。
    对了。。。什么是置换群...
    上网查啊!!!
    0
    回复 southstarj1发表于2007-10-02 18:50
    思想:
    置换群。(相关知识自己查)
    对于一组数据,按各人的意愿排出一个序列,
    如果无法排出,就输出-1。
    再将环状序列变成链状,则这个目标序列为一个置换群,
    与原序列(按1到n的一列)满足:
    交换的最少人数等于目标序列与原序列不重合的人数。
    因为总共有2n个目标序列(正反各n种),都算一遍就行了。
    步骤:
    读入数据;
    构造一个目标序列;
    统计该序列中元素位置与该元素在原序列位置的差值(同一方向)为i{i ∈ [0, n)}的元素个数;
    将该序列的反序统计一遍;
    从这些数据中选取一个最大的值max;
    输出n - max;
    注意:
    构造目标序列时判断能否构造的条件;
    统计一次差值的复杂度是O(n);
    统计差值的目的是求与原序列最多的重合人数;
    0
    回复 wangjin5发表于2007-09-19 22:38
    好经典的题奥
    确实有难度
    0
    回复 the_melody发表于2007-09-03 17:58
    Accepted 有效得分:100 有效耗时:0ms
    好经典的题奥
    0
    回复 richardxx发表于2007-08-22 17:36
    下面程序是错的,不好意思,弄错地方了....
    0
    回复 sm-star发表于2007-08-21 15:18
    题目所求就是每次进行连续交换的人数总和,这样,一个看似复杂的题目就变的异常的简单了!
    0
    回复 wasyyyy发表于2007-08-11 02:05
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms
    Accepted 有效得分:100 有效耗时:0ms
    HOHO~~~看讨论的时候看到有人提到‘置换群’这个东西,突然想起来我刚买的一本组合数学上有这么一块东西,就拿过来看了。。。。
    然后就出现上面的东西了。。。。置换群,本来想求轮换的,发现轮换比较多,还是找不参与交换的比较好记。。。。
    优化的方法。。。我看了下好象不只一个人讲过了。。。而且似乎我跟他们的都一样(没仔细看)所以就不说了。。。效率是O(n)的。。不用建环。
    0
    回复 angieqiu发表于2007-08-10 22:49
    怎么判断建环失败啊?我的程序虽然AC但总觉得方法很傻
    0
    回复 梦ぁ逍遥发表于2007-07-17 13:45
    想到了用t[i]=b[i]-i表示环
    却没想到镜像..
    十分感谢visister
    让我从90分中挣扎出来...
    0
    回复 visister发表于2007-06-01 00:12
    首先明显地可以知道我们需要对于目标状态建立出一个环。如果无法建立这个环,那么结果一定是-1,当建立好环以后可以知道最小移动代价一定等于最少的不在目标位置上的人数。那么我们可以对目标环进行顺时针旋转1~n-1之中任意一个,答案就一定等于旋转中的不在自己位置上的人数最少的那样的环的状态。但是对于50000的数据,我们如果要将环旋转1~n-1次,那么总共加上判断不在自己位置上的人数时间复杂度为O(n^2),显然在限定时间内是无法出解的。因此我们进行逆向思维:不在自己位置上最少的人数就一定会等于总人数减去在自己位置上最多的人数(仔细想想),那么我们就将该问题转化为了求在自己的位置上最多的人数,这样一来,我们对初始目标环中每一个位置进行判断需要旋转多少次可以回到自己位置上,每一个人的选择都将映射到[0..n-1]的数组中,选取当中最大的情况就为所求,但是考虑到环可以反转,那么我们还需要将环再求一次镜像,就可以得到初始目标需要旋转多少次可以得到在自己位置上最多的人数的环的状态,最后通过总的人数减去它即为问题所求,时间复杂度为O(n);
    0
    回复 pyh119发表于2006-11-16 20:11
    哪个人不小心失火了找我啊!!!
    PS:我是安徽省芜湖市119接线员....
    0
    回复 maomingming发表于2006-11-06 18:40
    考虑旋转后最多可能重合的情况,另要注意圈可以反过来
    0
    回复 qian5发表于2006-09-30 21:35
    直接输出‘-1’有一个点过
    0
    回复 BambooLeaf发表于2006-09-26 18:17
    见过的最牛最简单的方法……
    将此题转换为冒泡排序,记录下所有交换的次数和两数间的距离,加上就行了……—__—|||
    具体是这样的,我们反向思维,本来是要求一个有序数列求出成为无序数列的代价,现在我们把无序数列(即目标数列)进行冒泡排序,然后……就是这样……
    看完之后,偶巨汗……
    0
    回复 xcjzj发表于2006-09-26 17:18
    每组数据确定两组相对位置关系,并且这两组互为镜像。
    对于某一种排列方式,不在需要位置上的人数即为当前状态到目标状态的最小代价。
    先找出其中一种排列方式。由于目标状态可以通过旋转而使得部分人的变化次数减少,所以找出每个人通过某一固定方向旋转到达目标位置的旋转次数。找到某一次数,使得拥有这个次数的人数最多。那么,通过旋转这一最多人拥有的次数,即可使得尽可能多的人不通过交换直接到达目标位置。于是,不拥有这一旋转次数的人数即为这一状态下的最小代价。
    然后,用现在的目标状态找出其镜像状态,并且用上述方法再找一遍最小代价,与前面的结果比较,较小值即为答案。
    另外,题目中会出现一些无解的情况:
    1.某个人被“要”的次数多于两次,也就是说有多于两个的人想要与他(她)邻座,那么无解。
    2.根据要求得出的目标状态为多于一个的环,也无解。
    0
    回复 东邪歪刀发表于2006-07-28 17:27
    提交了若干次……残念……
    0
    回复 sugar发表于2006-07-28 16:26
    这题比赛时真有人ac?
    真不好想
    为什么得开longint啊?
    0
    回复 晶星发表于2006-07-25 13:29
    排列本质不同的只有二种 正着和反着的
    检验几个人不在位置上用数学方法:)模拟法超时的
    0
    回复 tzkq发表于2006-07-23 04:37
    注意别误解题意 b1,b2....bm并不指连续位置上的数
    0
    回复 Coldwings发表于2006-01-26 09:21
    可以用群论证明:如果有k个人不在自己的位置上,那么要且仅要k的代价,即可使这些人归位
    剩下的..很简单了吧...
    0
    回复 lemon_cn发表于2008-08-08 15:55
    热烈庆祝用pascal AC的第二题~
    p.s.我是C++的~~

    0

    回复 yingjiangyu发表于2015-02-15 21:55
    打‘Wrong!’有50分。。

    0

    回复 东大微雕发表于2015-02-07 15:20
    这道题真是太好了。奇妙无穷。
    #include<iostream>
    #include<string.h>
    #include<stdio.h>
    using namespace std;
    int a[50005];
    int size;
    void go(){
    int i, j;
    int ans = 0;
    int dis[50005];
    memset(dis, 0, sizeof(dis));
    for (i = 1; i <= size; i++){
    int d = (a[i] - i + size) % size;
    dis[d]++;
    }
    for (i = 0; i < size; i++){
    if (ans < dis[i])
    ans = dis[i];
    }
    memset(dis, 0, sizeof(dis));
    for (i = 1; i <= size; i++){
    int d = (a[size+1-i]-i+size) % size;
    dis[d]++;
    }
    for (i = 0; i < size; i++){
    if (ans < dis[i])ans = dis[i];
    }
    cout << size-ans << endl;
    }
    int main(){
    freopen("in.txt", "r", stdin);
    int neibor[50005][2];
    int i;
    cin >> size;
    for (i = 1; i <= size; i++){
    scanf("%d%d",&neibor[i][0],& neibor[i][1]);
    }
    bool used[50005];
    memset(used, 0, sizeof(used));
    a[1] = 1;
    used[1] = true;
    for (i = 2; i <= size; i++){
    int last = a[i - 1];
    if (!used[neibor[last][0]]){
    a[i] = neibor[last][0];
    used[a[i]] = true;
    }
    else if (!used[neibor[last][1]]){
    a[i] = neibor[last][1];
    used[a[i]] = true;
    }
    else {
    cout << -1 << endl;
    return 0;
    }
    }

    if (neibor[1][0] != a[size] && neibor[1][1] != a[size]){
    cout << -1 << endl;
    return 0;
    }
    go();
    return 0;
    }

    0

    回复 3516发表于2014-07-30 08:59
    include<stdio.h>

    include<string.h>

    int data[50001][2],shi[50001],a[50001];
    int main()
    {
    int n,i,j,qian,hou; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d%d",&data[i][0],&data[i][1]); } a[1]=1;shi[a[1]]=1 for(i=2;i<=n;i++) { qian=data[a[i-1]][0]; hou=data[a[i-1]][1]; if(shi[qian]==0) { a[i]=qian; shi[qian]=1; } else if(shi[hou]==0) { a[i]=hou; shi[hou]=1; } else { printf("-1"); return 0; } } int temp=0,max=0; memset(shi,0,sizeof(shi)); for(i=1;i<=n;i++) { temp=(n+a[i]-i+1)%n; shi[temp]++; } for(i=0;i<n;i++) { if(max<shi[i]) { max=shi[i]; } } memset(shi,0,sizeof(shi)); for(i=1;i<=n;i++) { temp=(n+a[n-i+1]-i+1)%n; shi[temp]++;
    }
    for(i=0;i<n;i++)
    {
    if(max<shi[i])max=shi[i];
    }
    printf("%d",n-max);
    }

    0

    回复 S.Y.F发表于2013-08-31 14:04
    题解
    1111111129回复于2014-08-13 11:52
    orzorzorz

    0

    回复 S.Y.F发表于2013-07-29 16:55
    从10、到30、到100。。。。。。
    题解:http://blog.163.com/syf_light_feather/blog/static/223755067201362945326756/

    0

    回复 vcvycy发表于2013-06-30 00:56
    20 30 40 50 70 分都有~泪流满面.
    Accepted

    100
    772 2

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:55:05
    Wrong Answer

    70
    613 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:53:24
    Wrong Answer

    70
    686 2

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:45:35
    Wrong Answer

    70
    856 2

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:42:12
    Wrong Answer

    70
    803 2

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:37:26
    Wrong Answer

    70
    882 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:22:39
    Wrong Answer

    70
    1145 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:20:30
    Wrong Answer

    10
    733 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:11:30
    Wrong Answer

    50
    723 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:04:20
    Wrong Answer

    50
    781 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:55:49
    Wrong Answer

    40
    656 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:49:49
    Wrong Answer

    40
    758 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:44:00
    Time Exceeded

    30
    7160 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:38:22
    Time Exceeded

    20
    7135 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:35:08

    0

    回复 SEX丶Elope发表于2013-02-16 10:10
    点击查看程序源码+详细题解
    cuichen回复于2014-09-09 09:24
    怎么又是你??你有什么企图?骗访问量???垃圾!

    0

    回复 qyjubriskxp发表于2010-07-09 21:31
    再一次体会到c++流的悲剧,秒杀和3s原来只是输入方式的不同,杯具~~
    yuyilahanbao回复于2014-01-24 11:47
    从c转到c++第一次不AC(除去忘记把语言有c改为c++的)就是因为c++输入输出的问题
    从那次起,我的c++的输入都是用scanf和printf了
    因为
    保险
    安全
    我记不清cin是<<还是>>
    printf和scanf相对更灵活
    ....

    0

    回复 slm发表于2010-03-16 18:27
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    嘿嘿

    0

    回复 superyoi发表于2009-11-10 11:50

    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    superyoi killed p1008 with a headshot by awp

    0

    回复 200853349发表于2009-11-10 10:49
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    当我看到众位神牛打出“置换群”三个字后,我在黑书百度GOOGLE维基百科逛了得有一个半小时多然后回来AC了。。。

    思路和strini神牛的基本一样。

    0

    回复 sinb发表于2009-11-09 13:02
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    其实很简单,不要想复杂了,先是想办法构成,然后用置换群的方法即可ac。

    0

    回复 香蕉派发表于2009-11-06 11:29
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    虽然不懂什么叫置换群,但是思路还是很清晰的。。

    0

    回复 赏金神侠PPF发表于2009-11-05 11:45
    一星星纪念~

    0

    回复 strini发表于2009-10-30 22:11
    根据群论原理,任何置换群都可以分解为若干个循环节。显然,这道题目就是冲着这点来的。因为如果某循环的长度为L,那么本题中只需要代价为L的操作。注意,这里的L!=1,这是因为只有一个人的循环节不需要任何代价的操作。到这里才只能拿三十分,因为圈是可以旋转的,常规方法需要O(n^2)才能解决。不妨这里以编号为1的人为基准,定义每个人到自己应该所在位置的距离。距离不超过n-1。可以通过最大值来寻找能在自己位置上的最多的人数(因为距离为x的人在旋转x次后转到自己的位置上),那么在比较好的情况下,可以优化到O(n)。

    TIME: 1H
    SUBMIT:
    1 70 Error: 发现希望相邻是不精确的,于是改了个搜索方向。(以为题目给定的是按照左右方向,白书说过不能“假定”!)。
    2 90 Error: 终于明白要取两个搜索方向的最大值。
    3 Accepted.


    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 skykey发表于2009-10-29 17:58
    #include<iostream>
    using namespace std;
    int n;
    int a[50001],b[50001],c[50001];
    int aim[50001];
    void G_MAP()
    {
    bool mark[50001]={false};
    int p=1,r=1;
    while(p<=n)
    {
    aim[p]=r;mark[r]=true;p++;
    if(!mark[a[r]])r=a[r];
    else if(!mark[b[r]])r=b[r];
    else if(p<=n){cout<<-1;exit(0);}
    }
    }
    int COMPULATE()
    {
    int max=0;
    int t;
    int record[2][50001];
    for(int i=1;i<=n;i++)record[0][i]=record[1][i]=0;
    for(int i=1;i<=n;i++)
    {
    if((t=aim[i]-i)<0)t+=n;
    record[0][t]++;
    if(record[0][t]>max)max=record[0][t];
    if((t=aim[i]-(n+1-i))<0)t+=n;
    record[1][t]++;
    if (record[1][t]>max)max=record[1][t];
    }
    return max;
    }
    int main()
    {
    cin>>n;
    for(int i=1;i<=n;i++)
    {scanf("%d%d",&a[i],&b[i]);c[a[i]]++;c[b[i]]++;}
    for(int i=1;i<=n;i++)if(c[i]!=2){cout<<-1;return 0;}

    G_MAP();
    int T=COMPULATE();
    cout<<n-T;
    }

    0

    回复 song19931218发表于2009-10-27 20:11
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    考虑两种情形(貌似这两种情形很像,但又真的不同,后来才想起,在化学的手性碳原子那部分遇到过类似情况。。。)
    然后就是运用置换群的知识

    0

    回复 Aries_C发表于2009-10-25 08:24
    正反两遍...两遍...<幽幽的声音飘远..>

    不然就是70分啊...

    不看题解的情况下竟然自己想到了...

    记得以前老师给我们做过这题的..细节什么的现在做又忘记了..唉..

    0

    回复 国防安全员001发表于2009-10-21 22:00
    Flag   Accepted
    题号   P1008
    类型(?)   模拟
    通过   1701人
    提交   4835次
    通过率   35%
    难度   3

    题目表述有问题。。

    0

    回复 liubosen发表于2009-10-21 21:50
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    yaaaayyayayyayayayayayayayayayayayayayayayyaayayayayayayyaayayayay
    var
    n,max,i:longint;
    a,b,c,d:array[0..50001] of longint;
    begin
    readln(n);
    for i:=1 to n do
    readln(a[i],b[i]);
    c[1]:=1;
    c[2]:=a[1];
    for i:=3 to n do
    if c=a[c] then c[i]:=b[c]
    else
    if c=b[c] then c[i]:=a[c]
    else begin
    writeln(-1);
    halt
    end;
    if c[n]<>b[1] then
    begin
    writeln(-1);
    halt
    end;
    fillchar(d,sizeof(d),0);
    for i:=1 to n do
    inc(d[(c[i]-i+n)mod n]);
    for i:=0 to n-1 do
    if d[i]>max then max:=d[i];
    fillchar(d,sizeof(d),0);
    for i:=1 to n do
    inc(d[(c[i]+i-1)mod n]);
    for i:=0 to n-1 do
    if d[i]>max then max:=d[i];
    writeln(n-max);
    end.

    0

    回复 lishunzhi发表于2009-10-21 00:11
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    置换群,但建环是重点

    0

    回复 zebra发表于2009-10-03 09:48
    #include <iostream>
    #include <cassert>
    using namespace std;
    long N,seq[50001],p=1;
    class
    {
    private:
    long nbr[50001][3];
    bool flag[50001];
    bool isnbr(long v1,long v2)
    {
    for(int i=1;i<=nbr[v1][0];i++)
    if(nbr[v1][i]==v2)
    return true;
    return false;
    }
    public:
    bool AddE(long v1,long v2)
    {
    if(isnbr(v1,v2))
    return true;
    else
    if(nbr[v1][0]==2||nbr[v2][0]==2)
    return false;
    else
    {
    nbr[v1][++nbr[v1][0]]=v2;
    nbr[v2][++nbr[v2][0]]=v1;
    return true;
    }
    }
    void dfs(long i)
    {
    assert(!flag[i]);
    flag[i]=true,seq[p++]=i;
    for(int j=1;j<=nbr[i][0];j++)
    {
    if(!flag[nbr[i][j]])
    {
    dfs(nbr[i][j]);
    break;
    }
    }
    }
    }G;
    long solve()
    {
    long cnt1[50001]={0},cnt2[50001]={0},ans=0;
    for(int i=1,a,b;i<=N;i++){
    a=seq[i]-i;
    if(a<0) a+=N;
    b=seq[i]-(N+1-i);
    if(b<0) b+=N;
    if(++cnt1[a]>ans) ans=cnt1[a];
    if(++cnt2>ans) ans=cnt2;
    }
    return N-ans;
    }
    int main()
    {
    cin >> N;
    for(int i=1,nbr1,nbr2;i<=N;i++)
    {
    cin >> nbr1 >> nbr2;
    if(!G.AddE(i,nbr1)||!G.AddE(i,nbr2))
    {
    cout << -1 << endl;
    return 0;
    }
    }
    G.dfs(1);
    cout << solve() << endl;
    system("pause");
    return 0;
    }

    0

    回复 -117-Join发表于2009-09-18 21:29
    哪位大牛帮忙看看我错哪里了
    它只得90分
    program fire;
    type
    arr=record
    l,r:longint;
    end;
    var
    num:array[1..50000]of longint;
    a:array[1..50000]of arr;
    b:array[1..50000]of longint;
    i,k,j,n:longint;
    begin
    readln(n);
    for i:=1 to n do
    readln(a[i].l,a[i].r);
    b[1]:=1;
    b[n]:=a[1].l;
    if a[b[n]].l=b[1]then b[n-1]:=a[b[n]].r
    else b[n-1]:=a[b[n]].l;
    i:=n-1;
    b[2]:=a[1].r;
    j:=2;
    while j<=i do
    begin
    if b<>a[b[i]].l then b:=a[b[i]].l
    else b:=a[b[i]].r;
    dec(i);
    if b[j-1]<>a[b[j]].r then b[j+1]:=a[b[j]].r
    else b[j+1]:=a[b[j]].l;
    inc(j);
    end;
    for i:=2 to n-1 do
    if(b<>a[b[i]].r)and(b<>a[b[i]].l)or(b<>a[b[i]].r)and(b<>a[b[i]].l)then
    begin
    write(-1);
    halt
    end;
    if(b[n]<>a[b[1]].l)and(b[n]<>a[b[1]].r)or(b[2]<>a[b[1]].l)and(b[2]<>a[b[1]].r)or(b[1]<>a[b[n]].l)and(b[1]<>a[b[n]].r)or(b[n-1]<>a[b[n]].l)and(b[n-1]<>a[b[n]].r)then
    begin
    write(-1);
    halt
    end;
    num[0]:=0;
    for i:=1 to n do
    begin
    a[b[i]].l:=i;
    num[i]:=0;
    end;
    for i:=1 to n do
    if a[i].l-i>=0 then inc(num[a[i].l-i])
    else inc(num[a[i].l-i+n]);
    j:=0;
    for i:=0 to n do
    if num[i]>j then j:=num[i];
    write(n-j);
    end.
    写的有点长

    0

    回复 fs302发表于2009-09-17 20:13
    分析:学一个好思想:正难则反!由顺序到乱序我们很难快速找到,但是我们知道如何从乱序变为顺序!解决本题利用了组合数学中置换群的思想。

    从第一个人处断开,将圆环的问题转化为序列的问题。如果可以,求出目标序列。求出目标序列复杂度O(n).
    求出目标序列右移0至n-1位置时,不需要移动的人数。将目标序列反转,再求出目标序列右移0至n-1位置时,不需要移动的人数。求不需要移动的人数最大等价于求需要移动的人数最小。复杂度O(n)。
    更详细的说:
    引进“相对有序”这个概念,当两个人满足C[j]-C[i]==j-i时,两个相对有序。
    题目要求最小的总代价,但是我们可以考虑倒过来想,要求最小的总代价亦即求最多有多少人不用移动,亦即相对有序。
    然后我们引进一个辅助变量T=C-I,{C-I>=0},T=C[i]-I+N,{C[i]-I<0},那么这个T[i]有什么意义呢?我们知道初始状态的编号是1-N,而目标状态是C[1]-C[N],那么C-I便是从目标状态到初始状态顺时针所要移动的距离,那么如果那么T值相等的两个同学则是相对有序的,亦即不用移动,我们只要找出最大的T然后N-Max(T)就是得到的结果,但是这样还不够,因为刚刚那样只是顺时针所要移动的距离,我们还要计算逆时针的到的结果,从顺时针和逆时针中找到最大的T,然后N-Max(T)才能够是正确结果.

    0

    回复 maxint64发表于2009-09-01 21:33
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    先是物理大发了——以为 b1,b2...bm是连续的
    看了牛们的题解 一次ac :)

    0

    回复 柔情使者发表于2009-08-20 15:44
    第一遍做的时候没有看题解,自己测了好几遍总是60分,看了n多大牛的解释才恍然大悟,竟然要正反两遍!!!唉,幸亏咱有测试数据,否则我可就惨了...
    O(n)的求目标队列算法,都说是冒泡排序,我没看出来,倒是有点像。

    0

    回复 maxiem发表于2009-08-18 20:55
    物理自重啊,嘿嘿。
    注意要正反两遍哦~
    9MS?
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 9ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:9ms

    (好像那个冒泡是口胡,大家不要被那个蒙了

    program fire;
    var
    st:array [1..50000,1..2] of longint;
    k,final:array [0..50000] of longint;
    ex:array [1..50000] of boolean;
    p,max,i,n:longint;
    begin
    fillchar (st,sizeof(st),0);
    fillchar (ex,sizeof(ex),0);
    fillchar (final,sizeof(final),0);
    fillchar (k,sizeof(k),0);
    readln (n);
    for i:=1 to n do readln (st,st);
    final[1]:=1;p:=2;ex[1]:=true;
    for i:=1 to n do begin
    if ex[st[final[i],1]]=false then begin
    final[p]:=st[final[i],1];
    ex[st[final[i],1]]:=true;
    inc(p);
    end
    else if ex[st[final[i],2]]=false then begin
    final[p]:=st[final[i],2];
    ex[st[final[i],2]]:=true;
    inc(p);
    end;
    end;
    if p-1<>n then begin
    writeln (-1);
    halt;
    end;
    max:=0;
    for i:=1 to n do if final[i]>=i then inc(k[final[i]-i]) else inc(k[n-i+final[i]]);
    for i:=0 to n-1 do if k[i]>max then max:=k[i];
    fillchar (k,sizeof(k),0);
    for i:=n downto 1 do if final[i]>=n-i+1 then inc(k[final[i]-n+i-1]) else inc(k[final[i]+i-1]);
    for i:=0 to n -1 do if k[i]>max then max:=k[i];
    writeln (n-max);
    end.

    0

    回复 suning发表于2009-08-14 09:43
    啊呜~
    一年前误解了题意~
    一年后理解了题意~
    然后就是1次美妙的AC

    PS:[误]解[理]解~~~[物理]?

    0

    回复 fengwuliu发表于2009-08-13 17:20
    lgxcgd说的太对了!太感谢了5555

    0

    回复 Matt发表于2009-08-11 22:28
    NOIP也会考高等数学...

    由于原图是环,所以置换群可表示为一次循环。作差是个好方法。

    但求冒泡排序是怎么作的

    0

    回复 3830372发表于2009-08-11 21:28
    Flag   Accepted
    题号   P1008
    类型(?)   模拟
    通过   1504人
    提交   4282次
    通过率   35%
    难度   3

    提交 讨论 题解 状态

    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 尖端才子发表于2009-08-11 11:14
    纪念一下……第1500个AC……

    Flag    Accepted
    题号   P1008
    类型(?)   模拟
    通过   1500人
    提交   4274次
    通过率   35%
    难度   3

    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 SecretAgent发表于2009-08-10 14:02
    置换群是正解

    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 yangbei发表于2009-08-07 14:57
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 338ms
    ├ 测试数据 05:答案正确... 322ms
    ├ 测试数据 06:答案正确... 306ms
    ├ 测试数据 07:答案正确... 338ms
    ├ 测试数据 08:答案正确... 338ms
    ├ 测试数据 09:答案正确... 322ms

    ├ 测试数据 10:答案正确... 306ms

    Accepted 有效得分:100 有效耗时:2270ms

    算镜像时偷了点懒,不过也算一遍AC了

    0

    回复 ja_son发表于2009-08-06 15:44
    a:拆环成队,寻求目标队列。
    b:b1,b2...bm不是连续的,而且是任意的。只要有成立目标队列,与原来的队列相匹配就可以知道有多少(设为n个)需要移动位置,则代价就是n。
    c:目标队列有多种情况,可以反转,也可以左右移动。

    0

    回复 1s发表于2009-08-03 17:56

    如对本题有疑问可以参看我的题解:
    http://xujieqi.blog.hexun.com/35722312_d.html

    0

    回复 DMKaplony发表于2009-07-30 15:15
    当时的时间限制好像是2s。。有个题解说把1定为第一项然后进行冒泡排序。。不过这里是1s 啊。。。也行只有置换群了吧。

    0

    回复 xusc_2009发表于2009-07-28 14:30
    看不懂,只好搁浅
    什么时候想清楚了再做

    0

    回复 董发表于2009-07-24 19:11
    program p1008;
    var i,n,k,j,sum1,sum2,ans,max:longint;
       a,b,w,d,c:array[0..50005] of longint;

    begin
    readln(n);
    for i:=1 to n do
    readln(a[i],b[i]);
    w[1]:=1; w[2]:=a[w[1]];
    k:=1;

    repeat
    inc(k);
    if w[k-1]=a[w[k]] then w[k+1]:=b[w[k]]
      else if w[k-1]=b[w[k]] then w[k+1]:=a[w[k]]
       else begin
           writeln(-1);
           exit;
           end;
    until k=n;
    if w[n+1]<>w[1] then
           begin
           writeln(-1);
           exit;
           end;

    for i:=1 to n do
    begin
    a[i]:=w[i]-i;
    b[i]:=w[n-i+1]-i;
    if a[i]<0 then a[i]:=a[i]+n;
    if b[i]<0 then b[i]:=b[i]+n;
    inc(c[a[i]]);
    inc(d[b[i]]);
    end;
    for i:=0 to n-1 do
    begin
    if ans<c[i] then ans:=c[i];
    if ans<d[i] then ans:=d[i];
    end;
    writeln(n-ans);  
    end.

    0

    回复 我飞发表于2009-07-23 21:00
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 93狒狒发表于2009-07-23 20:59
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    秒杀......

    0

    回复 fjxmlhx发表于2009-07-22 13:15
    置换群,做2n次,顺时针和逆时针.
    对于一个置换,最小操作费用是所有循环长度的和.因此实际上是找出2n个置换中哪个置换循环长度为1的数量最多.

    0

    回复 340508965发表于2009-07-21 15:01
    ⊙﹏⊙b汗
    不知道的以为这是数学竞赛......
    ...
    我的数论与图论可以说脑袋里空白一片.........
    怎么办,我的竞赛啊
    ........

    算了 看了题解 大家写的
    总算弄懂这道题了
    先前以为b1,b2,b3..bm是连续的
    没想到是任意的!!!!!!!!!

    诶 叹悲歌未切 为撼奈何编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    总算AC了


    program p1008;
    var i,n,k,j,sum1,sum2,ans,max:longint;
    a,b,w,d,c:array[0..50005] of longint;

    begin
    readln(n);
    for i:=1 to n do
    readln(a[i],b[i]);
    w[1]:=1; w[2]:=a[w[1]];
    k:=1;

    repeat
    inc(k);
    if w[k-1]=a[w[k]] then w[k+1]:=b[w[k]]
    else if w[k-1]=b[w[k]] then w[k+1]:=a[w[k]]
    else begin
    writeln(-1);
    exit;
    end;
    until k=n;
    if w[n+1]<>w[1] then
    begin
    writeln(-1);
    exit;
    end;

    for i:=1 to n do
    begin
    a[i]:=w[i]-i;
    b[i]:=w[n-i+1]-i;
    if a[i]<0 then a[i]:=a[i]+n;
    if b[i]<0 then b[i]:=b[i]+n;
    inc(c[a[i]]);
    inc(d[b[i]]);
    end;
    for i:=0 to n-1 do
    begin
    if ans<c[i] then ans:=c[i];
    if ans<d[i] then ans:=d[i];
    end;
    writeln(n-ans);
    end.

    0

    回复 zsy90943发表于2009-07-18 00:51
    构造巧妙、、看来还是要学好数论和图论额、、、、

    0

    回复 POM无敌牛B发表于2009-07-16 11:47
    编译通过...
    ├ 测试数据 01:运行超时...
    ├ 测试数据 02:运行超时...
    ├ 测试数据 03:运行超时...
    ├ 测试数据 04:运行超时...
    ├ 测试数据 05:运行超时...
    ├ 测试数据 06:运行超时...
    ├ 测试数据 07:运行超时...
    ├ 测试数据 08:运行超时...
    ├ 测试数据 09:运行超时...

    ├ 测试数据 10:运行超时...

    Unaccepted 有效得分:0 有效耗时:0ms
    无奈 哪位哥哥救救我

    0

    回复 yxy发表于2009-06-16 18:16
    把置换解释成度为2图,真有才.
    求出序列,正反分别做一次差就行了.

    0

    回复 sxpeter发表于2009-06-14 16:56
    讲建环吧。数组w表示环,我用的是一种类似并查集的方法。
    begin
    read(n);
    for i:=1 to n do read(a[i],b[i]);
    t:=2;w[1]:=1;w[2]:=a[1];
    while true do begin
    if a[w[t]]<>w[t-1]then w[t+1]:=a[w[t]]//是否在左边
    else if b[w[t]]<>w[t-1]then w[t+1]:=b[w[t]]//是否在右边
    else begin writeln(-1);halt;end;//失败判断
    inc(t);
    if t>n then break;
    end;
    if w[n+1]<>w[1]then begin writeln(-1);halt;end;//本句一定要加!!!!!!
    end.

    0

    回复 lgxcgd发表于2009-05-17 20:24
    首先把这个圈看做一个图,每个同学看做一个顶点。因为要形成环,所以每个顶点的度必须为2。

    如果存在度数不为2的顶点,那么整个图无法构成一个环,即“无论怎么调整都不能符合每个同学的愿望”输出-1。

    如果是一个环,那么就遍历图,生成以第1个顶点为开头的序列。现在就要求出最小移动的代价。

    在理解题意所述的调整方式中,要注意实际上就是把M个在错误位置上的人移动到正确的位置上,代价为M。一次下令移动即可。

    假如生成的目标序列为1,5,3,2,4。我们现在就需要比较它和初始状态1,2,3,4,5,看有几个人离开了原来的位置。但这个序列实际代表的是一个环,而且方向正反有两种,就需要把初始序列正反分别转N次,和得到的序列比较,看其中最少有几个位置上的人编号不相同,就得到了我们要求的最小代价。

    上述方法有大量冗余。但可以发现转来转去不管怎么转,任意两个人之间的相对位置关系在这过程中都不会变。于是想到做差,如果差小于0则加上N。

    1 5 3 2 4

    - 1 2 3 4 5

    0 3 0 3 4
    这表示序列1,5,3,2,4不转动时1,3两个人在原来的位置上,转动3个位置后5和2两个人在原来的位置上,转动4个位置后只有4一个人会在原来的位置上。这就是说,1,5,3,2,4与1,2,3,4,5在旋转后最多有2个位置上的人编号相同,即最少有3个位置上的人编号不相同。同理要反转再求一次。

    记录每个不同的差值的个数,取其最大值P,即不调换次数最大的。结果N-P就是调换次数最小的。

    0

    回复 src250发表于2009-05-14 08:27

    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    切记:重新构图时一定要对数组清空!我的第一次只有50分,就是这个原因!

    0

    回复 love19960108发表于2009-04-26 17:59
    这题可以用C++这样做么??
    #include <iostream>
    #include <cassert>
    using namespace std;
    long N,seq[50001],p=1;
    class{
    private:
    long nbr[50001][3];
    bool flag[50001];
    bool isnbr(long v1,long v2){
    for(int i=1;i<=nbr[v1][0];i++)
    if(nbr[v1][i]==v2) return true;
    return false;
    }
    public:
    bool AddE(long v1,long v2){
    if(isnbr(v1,v2)) return true;
    else if(nbr[v1][0]==2||nbr[v2][0]==2) return false;
    else{
    nbr[v1][++nbr[v1][0]]=v2;
    nbr[v2][++nbr[v2][0]]=v1;
    return true;
    }
    }
    void dfs(long i){
    assert(!flag[i]);
    flag[i]=true,seq[p++]=i;
    for(int j=1;j<=nbr[i][0];j++){
    if(!flag[nbr[i][j]]){
    dfs(nbr[i][j]);
    break;
    }
    }
    }
    }G;
    long solve(){
    long cnt1[50001]={0},cnt2[50001]={0},ans=0;
    for(int i=1,a,b;i<=N;i++){
    a=seq[i]-i;
    if(a<0) a+=N;
    b=seq[i]-(N+1-i);
    if(b<0) b+=N;
    if(++cnt1[a]>ans) ans=cnt1[a];
    if(++cnt2>ans) ans=cnt2;
    }
    return N-ans;
    }
    int main(){
    cin >> N;
    for(int i=1,nbr1,nbr2;i<=N;i++){
    cin >> nbr1 >> nbr2;
    if(!G.AddE(i,nbr1)||!G.AddE(i,nbr2)){
    cout << -1 << endl;
    return 0;
    }
    }
    G.dfs(1);
    cout << solve() << endl;
    return 0;
    }

    0

    回复 voyagec2发表于2009-03-18 15:53
    难理解,不过算法很精妙

    0

    回复 pRoevollove发表于2009-02-25 23:49
    天,把(p[i]-i+n)mod n理所当然地打成了abs(p[i]-i)
    结果一直50分……还一直以为自己构造错了……

    ps 我可以过楼下的范例哦

    0

    回复 ufo172849z发表于2009-01-24 23:05
    ms楼下的程序不能处理这种反例(测试数据还是不够强啊)
    6
    2 3
    1 3
    1 2
    5 6
    4 6
    4 5
    应该输出-1的吧?因为是两个环

    var a,b:array[0..50000]of longint;
    c:array[0..50000,1..2]of longint;
    d:array[0..50000]of boolean;
    i,j,k,m,n,max:longint;
    can:boolean;

    begin
    readln(n);
    for i:=1 to n do
    readln(c,c);
    b[0]:=c[1,1]; b[n]:=c[1,1];
    fillchar(d,sizeof(d),0);
    k:=1;
    can:=true;
    for i:=1 to n-1 do
    begin
    if d[k] then can:=false;
    b[i]:=k; d[k]:=true;
    if b=c[k,1] then k:=c[k,2]
    else if b=c[k,2] then k:=c[k,1]
    else can:=false;
    if not can then break;
    end;
    if can then
    if b[n]<>k then can:=false;
    if can then
    begin
    max:=-1;
    fillchar(a,sizeof(a),0);
    for i:=1 to n do
    inc(a[(b[i]-i+n) mod n]);
    for i:=0 to n-1 do
    if a[i]>max then max:=a[i];
    fillchar(a,sizeof(a),0);
    for i:=1 to n do
    inc(a[(b[n-i+1]-i+n)mod n]);
    for i:=1 to n-1 do
    if a[i]>max then max:=a[i];
    writeln(n-max);
    end
    else
    writeln(-1);
    end.

    0

    回复 tangdongjian发表于2009-01-23 22:17
    我在做镜像时把原先max直接覆盖上了,注意

    0

    回复 永恒888发表于2009-10-26 22:50
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 tangkunjie发表于2009-06-04 19:50
    挺烦人的题目

    0

    回复 ykspeter发表于2008-11-13 20:32
    program fire(input,output);
    var
    n,i,j,k,max,v:longint;
    a:array[0..100000,1..2] of longint;
    b,c:array[0..100000] of longint;
    begin
    readln(n);
    for i:=1 to n do readln(a,a);
    for i:=1 to n do
       begin
        k:=0;
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if (k=4) or (k=3)
        then begin
           writeln('-1');
           exit
           end
       end;
    b[1]:=1;i:=2;k:=a[1,1];j:=1;
    repeat
      b[i]:=k;
      inc(i);
      v:=k;
      if a[k,1]<>j
      then k:=a[k,1]
      else k:=a[k,2];
      j:=v;
    until i=n+1;
    fillchar(c,sizeof(c),0);
    for i:=1 to n do inc(c[(b[i]-i+n)mod n]);
    for i:=0 to n-1 do
       if c[i]>max
       then max:=c[i];
    fillchar(c,sizeof(c),0);max:=0;
    for i:=1 to n do inc(c[(b[n-i+1]-i+n)mod n]);
    for i:=n-1 downto 0 do
       if c[i]>max
       then max:=c[i];
    writeln(n-max);
    end.

    0

    回复 getuojian发表于2008-11-10 13:38
    #include<stdio.h>
    #include<memory.h>

    const int maxn=50010;
    int n;
    int f[maxn][2];
    int goal[maxn];
    int ans=maxn;
    int hash[maxn];

    bool SET_ORI(){
    bool flag[maxn];
    memset(flag, true, sizeof(flag));
    goal[1]=1; flag[1]=false;
    for (int i=1; i<=n-1; i++){
    if (flag[f[goal[i]][0]]){
    goal=f[goal[i]][0];
    flag[f[goal[i]][0]]=false;
    continue;
    }
    if (flag[f[goal[i]][1]]){
    goal=f[goal[i]][1];
    flag[f[goal[i]][1]]=false;
    continue;
    }
    return false;
    }
    if ((goal[n]!=f[1][0]) && (goal[n]!=f[1][1]))
    return false;
    return true;
    }
    int SWAP(int i, int j){
    int t=goal[i];
    goal[i]=goal[j];
    goal[j]=t;
    return 0;
    }

    int min(int i, int j){
    return i>j?j:i;
    }
    int HASH(){
    for(int i=1; i<=n; i++)
    hash[i]=goal[i]-i+n;
    return 0;
    }

    int CALC(){
    int temp[maxn*2], back=0;
    memset(temp, 0, sizeof(temp));
    for (int i=1; i<=n; i++)
    temp[hash[i]%n]++;
    for (int i=1; i<=2*n-1; i++)
    if (temp[i] > back)
    back=temp[i];
    return back;
    }

    int main(){
    freopen("fire.in", "r", stdin);
    freopen("fire.out", "w", stdout);
    scanf("%d", &n);
    for (int i=1; i<=n; i++)
    scanf("%d %d", &f[i][0], &f[i][1]);
    if (!SET_ORI()){
    printf("-1");
    return 0;
    }
    //forward
    HASH();
    ans=min(ans, n-CALC());
    //backward
    for (int i=1; i<=n/2; i++)
    SWAP(i,n-i+1);
    HASH();
    ans=min(ans, n-CALC());

    printf("%d", ans);
    return 0;
    }

    0

    回复 IVORY发表于2008-11-06 10:46
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    CHEAT的...

    0

    回复 storey p发表于2008-11-05 14:19
    回447389831:
    exit换成halt

    0

    回复 FenXy发表于2008-11-04 08:28
    艺术p245

    0

    回复 hlq发表于2008-11-01 14:31
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms

    求不在位置上的人数
    a【i】 第i位上的同学编号
    for i:=1 to n do
    begin
    inc(b[(a[i]-i+n) mod n])
    end;
    max:=0;
    for i:=0 to n-1 do
    if b[i]>max then max:=b[i];
    fillchar(b,sizeof(b),0);
    for i:=1 to n do
    begin
    inc(b[(a[i]-(n-i+1)+n)mod n]);//对称
    end;
    for i:=0 to n-1 do
    if b[i]>max then max:=b[i];

    0

    回复 Will~骷髅发表于2008-10-30 21:37
    编译通过...
    ├ 测试数据 01:运行超时...
    ├ 测试数据 02:运行超时...
    ├ 测试数据 03:运行时错误...|错误号: -1073741819
    ├ 测试数据 04:运行时错误...|错误号: -1073741819
    ├ 测试数据 05:运行时错误...|错误号: -1073741819
    ├ 测试数据 06:运行时错误...|错误号: -1073741819
    ├ 测试数据 07:运行时错误...|错误号: -1073741819
    ├ 测试数据 08:运行时错误...|错误号: -1073741819
    ├ 测试数据 09:运行时错误...|错误号: -1073741819

    ├ 测试数据 10:运行时错误...|错误号: -1073741819

    Unaccepted 有效得分:0 有效耗时:0ms

    怎么会这样???

    0

    回复 悲伤逆流成河发表于2008-10-28 22:13
    #include <iostream>
    #include <fstream>
    using namespace std ;

    int hash[50001];
    int n , i , j , t , maxs(0) ;

    inline void HASH ( int e[] )
    {
    for ( i = 1 ; i <= n ; i++ )
    {
    e[i] -= i ;
    if ( e[i] < 0 ) e[i] += n ;
    hash[e[i]]++ ;
    }
    for ( i = 0 ; i < 50001 ; i++ )
    if ( maxs < hash[i] ) maxs = hash[i] ;
    }

    int main(){
    ifstream fin ("fire.in") ;
    ofstream fout ("fire.out") ;

    fin >> n ;
    int e[n+1] , h[n+1][2] , e2[n+1];
    bool f[n+1] ;
    for ( i = 1 ; i <= n ; i++ )
    {
    f[i] = false ;
    fin >> h[i][0] >> h[i][1] ;
    }
    e[1] = 1 ;
    f[1] = true ;
    for ( i = 2 ; i <= n ; i++ )
    {
    if ( e < 0 ) { fout << -1 << endl ; exit(0) ; }
    if ( !f [ h[ e ][0] ] ) e[i] = h[ e ][0] ;
    if ( !f [ h[ e ][1] ] ) e[i] = h[ e ][1] ;
    f[ e[i] ] = true ;
    }
    for ( i = 1 , j = n ; i <= n ; i++,j-- ) e2[j] = e[i] ;
    HASH ( e ) ;
    memset ( hash , 0 , sizeof ( hash ) ) ;
    HASH ( e2 ) ;
    fout << n - maxs << endl ;
    }

    0

    回复 evelynhe发表于2008-10-26 16:31
    “置换群思想...今天刚明白...

    先构造新数列(要构造两次,否则只有70分),然后向右计算相对位置差,然后累加记录数组,然后用N减去相对位置差累加值最大的,就是答案... ”

    这是真的

    0

    回复 true1023发表于2008-10-25 09:32
    置换群的基本概念
    利用原序列和目标序列每个元素的绝对位置差来求出原序列每个元素对于目标序列的相对位置,找相对位置相同的最多的元素数,用总元素数减去它即为结果。

    0

    回复 447389831发表于2008-10-21 09:45
    program fire(input,output);
    var
    n,i,j,k,max,v:longint;
    a:array[0..100000,1..2] of longint;
    b,c:array[0..100000] of longint;
    begin
    readln(n);
    for i:=1 to n do readln(a,a);
    for i:=1 to n do
       begin
        k:=0;
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if (k=4) or (k=3)
        then begin
           writeln('-1');
           exit
           end
       end;
    b[1]:=1;i:=2;k:=a[1,1];j:=1;
    repeat
      b[i]:=k;
      inc(i);
      v:=k;
      if a[k,1]<>j
      then k:=a[k,1]
      else k:=a[k,2];
      j:=v;
    until i=n+1;
    fillchar(c,sizeof(c),0);
    for i:=1 to n do inc(c[(b[i]-i+n)mod n]);
    for i:=0 to n-1 do
       if c[i]>max
       then max:=c[i];
    fillchar(c,sizeof(c),0);max:=0;
    for i:=1 to n do inc(c[(b[n-i+1]-i+n)mod n]);
    for i:=n-1 downto 0 do
       if c[i]>max
       then max:=c[i];
    writeln(n-max);
    end.
    90 分,牛人门帮看下把

    0

    回复 cnfnje1发表于2008-10-17 18:12
    置换群.....是什么?
    readln(n);
    for i:=1 to n do readln(a[i],b[i]);
    c[1]:=1; c[2]:=a[1];
    for i:=3 to n do if c=a[c] then c[i]:=b[c]
    else if c=b[c] then c[i]:=a[c]
    else begin writeln(-1); halt end;
    if c[n]<>b[1] then begin writeln(-1); halt end;
    fillchar(d,sizeof(d),0);
    for i:=1 to n do inc(d[(c[i]-i+n)mod n]);
    for i:=0 to n-1 do if d[i]>m then m:=d[i];
    fillchar(d,sizeof(d),0);
    for i:=1 to n do inc(d[(c[i]+i-1)mod n]);
    for i:=0 to n-1 do if d[i]>m then m:=d[i];
    writeln(n-m);
    是么?

    0

    回复 lyrics发表于2008-10-12 19:55
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    技巧性比较强吧,楼下不必构造2次,计算时从头至尾算一次,再倒过来算一次就行了

    0

    回复 LV.唱响发表于2008-10-05 08:38
    置换群思想...今天刚明白...

    先构造新数列(要构造两次,否则只有70分),然后向右计算相对位置差,然后累加记录数组,然后用N减去相对位置差累加值最大的,就是答案...

    0

    回复 宇智波带波斯猫发表于2008-10-05 08:33
    Flag   Accepted
    题号   P1008
    类型(?)   其它
    通过   1065人
    提交   3000次
    通过率   35%
    难度   3

    第3000个提交的

    0

    回复 鸳鸯羡发表于2008-09-28 18:19
    #include <iostream>
    using namespace std ;

    int hash[50001];
    int n , i , j , t , maxs(0) ;

    inline void HASH ( int e[] )
    {
    for ( i = 1 ; i <= n ; i++ )
    {
    e[i] -= i ;
    if ( e[i] < 0 ) e[i] += n ;
    hash[e[i]]++ ;
    }
    for ( i = 0 ; i < 50001 ; i++ )
    if ( maxs < hash[i] ) maxs = hash[i] ;
    }

    int main(){
    cin >> n ;
    int e[n+1] , h[n+1][2] , e2[n+1];
    bool f[n+1] ;
    for ( i = 1 ; i <= n ; i++ )
    {
    f[i] = false ;
    cin >> h[i][0] >> h[i][1] ;
    }
    e[1] = 1 ;
    f[1] = true ;
    for ( i = 2 ; i <= n ; i++ )
    {
    if ( e < 0 ) { cout << -1 << endl ; exit(0) ; }
    if ( !f [ h[ e ][0] ] ) e[i] = h[ e ][0] ;
    if ( !f [ h[ e ][1] ] ) e[i] = h[ e ][1] ;
    f[ e[i] ] = true ;
    }
    for ( i = 1 , j = n ; i <= n ; i++,j-- ) e2[j] = e[i] ;
    HASH ( e ) ;
    memset ( hash , 0 , sizeof ( hash ) ) ;
    HASH ( e2 ) ;
    cout << n - maxs << endl ;
    }

    80分

    0

    回复 月光疾风发表于2008-09-25 13:03
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    纪念我第200次提交!过第79题。。。。

    0

    回复 ghostplant发表于2008-09-20 19:48
    #include <iostream>
    #include <fstream>
    #include <cassert>
    using namespace std;
    long N,seq[50001],p=1;
    class{
    private:
    long nbr[50001][3];
    bool flag[50001];
    bool isnbr(long v1,long v2){
    for(int i=1;i<=nbr[v1][0];i++)
    if(nbr[v1][i]==v2) return true;
    return false;
    }
    public:
    bool AddE(long v1,long v2){
    if(isnbr(v1,v2)) return true;
    else if(nbr[v1][0]==2||nbr[v2][0]==2) return false;
    else{
    nbr[v1][++nbr[v1][0]]=v2;
    nbr[v2][++nbr[v2][0]]=v1;
    return true;
    }
    }
    void dfs(long i){
    assert(!flag[i]);
    flag[i]=true,seq[p++]=i;
    for(int j=1;j<=nbr[i][0];j++){
    if(!flag[nbr[i][j]]){
    dfs(nbr[i][j]);
    break;
    }
    }
    }
    }G;
    long solve(void){
    long cnt1[50001]={0},cnt2[50001]={0},ans=0;
    for(int i=1,a,b;i<=N;i++){
    a=seq[i]-i;
    if(a<0) a+=N;
    b=seq[i]-(N+1-i);
    if(b<0) b+=N;
    if(++cnt1[a]>ans) ans=cnt1[a];
    if(++cnt2>ans) ans=cnt2;
    }
    return N-ans;
    }
    int main(){
    cin >> N;
    for(int i=1,nbr1,nbr2;i<=N;i++){
    cin >> nbr1 >> nbr2;
    if(!G.AddE(i,nbr1)||!G.AddE(i,nbr2)){
    cout << -1 << endl;
    return 0;
    }
    }
    G.dfs(1);
    cout << solve() << endl;
    return 0;
    }

    0

    回复 zzh19950802发表于2008-09-17 19:29
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案错误... ├ 标准行输出
     ├ 错误行输出
    ├ 测试数据 05:答案错误... ├ 标准行输出
     ├ 错误行输出
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 462ms
    ├ 测试数据 08:答案正确... 369ms
    ├ 测试数据 09:答案正确... 384ms
    ├ 测试数据 10:答案错误...程序输出比正确答案长
    为什么我的程序不对?
    #include <iostream>
    using namespace std;
    #define MAXN 50000
    int man[MAXN+2][2];
    int cercle[MAXN+2]={0,1};
    int used[MAXN+2]={0};
    int reduce[2][MAXN+2]={0};
    int n;
    int main()
    {
    long i,p,q=1,t;
    int max=0;
    cin>>n;
    for (i=1;i<=n;i++) cin>>man[i][0]>>man[i][1];
    p=man[q][1];
    for (i=2;i<=n+1;i++)
    {
    if (man[q][1]==p)
    {
    p=q;
    q=man[q][0];
    }
    else
    {
    if(man[q][0]!=p) break;
    p=q;
    q=man[q][1];
    }
    if(used[q]) break;
    else used[q]=1;
    cercle[i]=q;
    }
    if (i<=n+1) cout<<-1;
    else
    {
    for (i=1;i<=n;i++)
    {
    if((t=cercle[i]-i)<0) t+=n;
    reduce[0][t]++;
    if (reduce[0][t]>max) max=reduce[0][t];
    if ((t=cercle[i]-n+i-1)<0) t+=n;
    if (reduce[1][t]>max) max=reduce[1][t];
    }
    cout<<n-max;
    }
    return 0;
    }

    0

    回复 liaorc发表于2008-09-16 17:56
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 cxy450090074发表于2008-09-04 13:34
    oh no

    0

    回复 Lost.G发表于2008-08-22 15:49
    我在想``怎么样才能不看错这题呢

    0

    回复 bonism发表于2008-08-14 21:30
    时间复杂度O(N)。。。

    原来我一直把题意理解错。。。囧!!。。

    关于“置换群”,请看LRJ的《算法艺术与信息学竞赛》P245那一小节,还是比较好理解的。

    0

    回复 lemon_cn发表于2008-08-08 15:55
    热烈庆祝用pascal AC的第二题~
    p.s.我是C++的~~

    0

    回复 oipn4e2发表于2008-08-05 21:36
    解决效率不高,但AC了。

    0

    回复 notblack发表于2008-08-01 09:17
    用距离来分类,统计在原位的最大人数,奇怪的是
    b[1]:=1;
    b[2]:=a[1,1];
    b[n]:=a[1,2];

    建环的时候,上面的改成
    b[1]:=1;
    b[2]:=a[1,2];
    b[n]:=a[1,1];

    最后一个点却过不了,太奇怪了.

    0

    回复 332404521发表于2008-07-14 13:53
    对于初三刚刚中考完的我,要理解这题的意思是万万不能的。。。
    看题解我知道了应该怎么做,但那不是我的,所以不做了。。。
    哪天能证明出来那啥再来做

    0

    回复 Sheeta发表于2007-11-14 15:45
    好简单啊
    直接贪啊
    (P.S.置换群?什么东东...)

    0

    回复 mingyueyucai发表于2007-11-09 21:22
    我代码写了老长老长,结果还是只过了8个点,有没有搞错?
    我想请问一下,我和大家的一样,先排列出目标状态.然后确定初始状态时使得最多的人在目标位置上,然后交换.但是得到的答案总是偏大一点.
    然后我又把所有可以使最多的人在原位目标位置上的可能都尝试了一编(包括正反两个目标状态),结果还是只能过8个点,有2个点死都过不了!
    我的算法有什么问题吗?

    0

    回复 luanjiyang发表于2007-11-08 08:44
    很委琐的说 我提交了8遍。。
    0→0→10→10→10→10→70→AC

    • -||

    0

    回复 lonelycorn发表于2007-11-05 23:31
    数论……好底歇的东西。

    0

    回复 gamejifan发表于2007-11-04 11:15
    这题的叙述,让我误会了一年多。tzkq……3q..要早知道是这种意思早就ac了这题。。显然没什么大意思,看过组合数学或者学过群论的都懂。。ms跟polya计数法那个循环的意思。。

    写的时候竟然因为交换的时候写错一个字母wa。我汗。

    0

    回复 Alexandria发表于2007-11-01 13:33
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    好强大的题啊,不看题解还真不会!

    0

    回复 clfhaha1234发表于2007-10-30 18:09
    请问什么是置换群啊?可以讲讲吗?………………

    0

    回复 rleepas发表于2007-10-30 13:18
    楼下都是正解?
    ......

    0

    回复 Ice_Msk发表于2007-10-18 20:35
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    什么是置换群?不知道。。。照样过。。。。

    0

    回复 junlonely发表于2007-10-18 20:13
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 江南不才发表于2007-10-11 16:19
    排序法这里会超时~~~~~
    比赛的时间是2S~~
    这里是1S~~
    (_)

    0

    回复 秒杀群众发表于2007-10-10 17:05
    居然是置换群。。。
    对了。。。什么是置换群...
    上网查啊!!!

    0

    回复 southstarj1发表于2007-10-02 18:50
    思想:
    置换群。(相关知识自己查)
    对于一组数据,按各人的意愿排出一个序列,
    如果无法排出,就输出-1。
    再将环状序列变成链状,则这个目标序列为一个置换群,
    与原序列(按1到n的一列)满足:
    交换的最少人数等于目标序列与原序列不重合的人数。
    因为总共有2n个目标序列(正反各n种),都算一遍就行了。

    步骤:
    1. 读入数据;
    2. 构造一个目标序列;
    3. 统计该序列中元素位置与该元素在原序列位置的差值(同一方向)为i{i ∈ [0, n)}的元素个数;
    4. 将该序列的反序统计一遍;
    5. 从这些数据中选取一个最大的值max;
    6. 输出n - max;

    注意:
    构造目标序列时判断能否构造的条件;
    统计一次差值的复杂度是O(n);
    统计差值的目的是求与原序列最多的重合人数;

    0

    回复 wangjin5发表于2007-09-19 22:38
    好经典的题奥
    确实有难度

    0

    回复 the_melody发表于2007-09-03 17:58
    Accepted 有效得分:100 有效耗时:0ms
    好经典的题奥

    0

    回复 richardxx发表于2007-08-22 17:36
    下面程序是错的,不好意思,弄错地方了....

    0

    回复 sm-star发表于2007-08-21 15:18
    题目所求就是每次进行连续交换的人数总和,这样,一个看似复杂的题目就变的异常的简单了!

    0

    回复 wasyyyy发表于2007-08-11 02:05
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    HOHO~~~看讨论的时候看到有人提到‘置换群’这个东西,突然想起来我刚买的一本组合数学上有这么一块东西,就拿过来看了。。。。
    然后就出现上面的东西了。。。。置换群,本来想求轮换的,发现轮换比较多,还是找不参与交换的比较好记。。。。

    优化的方法。。。我看了下好象不只一个人讲过了。。。而且似乎我跟他们的都一样(没仔细看)所以就不说了。。。效率是O(n)的。。不用建环。

    0

    回复 angieqiu发表于2007-08-10 22:49
    怎么判断建环失败啊?我的程序虽然AC但总觉得方法很傻

    0

    回复 梦ぁ逍遥发表于2007-07-17 13:45
    想到了用t[i]=b[i]-i表示环
    却没想到镜像..

    十分感谢visister
    让我从90分中挣扎出来...

    0

    回复 visister发表于2007-06-01 00:12
    首先明显地可以知道我们需要对于目标状态建立出一个环。如果无法建立这个环,那么结果一定是-1,当建立好环以后可以知道最小移动代价一定等于最少的不在目标位置上的人数。那么我们可以对目标环进行顺时针旋转1~n-1之中任意一个,答案就一定等于旋转中的不在自己位置上的人数最少的那样的环的状态。但是对于50000的数据,我们如果要将环旋转1~n-1次,那么总共加上判断不在自己位置上的人数时间复杂度为O(n^2),显然在限定时间内是无法出解的。因此我们进行逆向思维:不在自己位置上最少的人数就一定会等于总人数减去在自己位置上最多的人数(仔细想想),那么我们就将该问题转化为了求在自己的位置上最多的人数,这样一来,我们对初始目标环中每一个位置进行判断需要旋转多少次可以回到自己位置上,每一个人的选择都将映射到[0..n-1]的数组中,选取当中最大的情况就为所求,但是考虑到环可以反转,那么我们还需要将环再求一次镜像,就可以得到初始目标需要旋转多少次可以得到在自己位置上最多的人数的环的状态,最后通过总的人数减去它即为问题所求,时间复杂度为O(n);

    0

    回复 pyh119发表于2006-11-16 20:11
    哪个人不小心失火了找我啊!!!

    PS:我是安徽省芜湖市119接线员....

    0

    回复 maomingming发表于2006-11-06 18:40
    考虑旋转后最多可能重合的情况,另要注意圈可以反过来

    0

    回复 qian5发表于2006-09-30 21:35
    直接输出‘-1’有一个点过

    0

    回复 BambooLeaf发表于2006-09-26 18:17
    见过的最牛最简单的方法……
    将此题转换为冒泡排序,记录下所有交换的次数和两数间的距离,加上就行了……—__—|||
    具体是这样的,我们反向思维,本来是要求一个有序数列求出成为无序数列的代价,现在我们把无序数列(即目标数列)进行冒泡排序,然后……就是这样……
    看完之后,偶巨汗……

    0

    回复 xcjzj发表于2006-09-26 17:18
    每组数据确定两组相对位置关系,并且这两组互为镜像。
    对于某一种排列方式,不在需要位置上的人数即为当前状态到目标状态的最小代价。
    先找出其中一种排列方式。由于目标状态可以通过旋转而使得部分人的变化次数减少,所以找出每个人通过某一固定方向旋转到达目标位置的旋转次数。找到某一次数,使得拥有这个次数的人数最多。那么,通过旋转这一最多人拥有的次数,即可使得尽可能多的人不通过交换直接到达目标位置。于是,不拥有这一旋转次数的人数即为这一状态下的最小代价。
    然后,用现在的目标状态找出其镜像状态,并且用上述方法再找一遍最小代价,与前面的结果比较,较小值即为答案。
    另外,题目中会出现一些无解的情况:
    1.某个人被“要”的次数多于两次,也就是说有多于两个的人想要与他(她)邻座,那么无解。
    2.根据要求得出的目标状态为多于一个的环,也无解。

    0

    回复 东邪歪刀发表于2006-07-28 17:27
    提交了若干次……残念……

    0

    回复 sugar发表于2006-07-28 16:26
    这题比赛时真有人ac?
    真不好想
    为什么得开longint啊?

    0

    回复 晶星发表于2006-07-25 13:29
    排列本质不同的只有二种 正着和反着的
    检验几个人不在位置上用数学方法:)模拟法超时的

    0

    回复 tzkq发表于2006-07-23 04:37
    注意别误解题意 b1,b2....bm并不指连续位置上的数

    0

    回复 Coldwings发表于2006-01-26 09:21
    可以用群论证明:如果有k个人不在自己的位置上,那么要且仅要k的代价,即可使这些人归位

    剩下的..很简单了吧...

    0

    回复 cxy450090074发表于2008-09-04 13:34
    oh no
    没有更多题解了 ╮(╯O╰)╭
    UPYUN
    评测机们

    树形图设计者
    上海红茶馆
    Jtwd2
    VijosEx
    Vijos 2.0 动态

    2014-9-25 备案完毕
    2014-9-28 更换服务器
    2014-11-28 微小更新
    2015-7-10 重新开启MC服务
    实验室 | API | 博客 | 帮助 | 隐私 | 联系 | 关于 | 沪ICP备14040537号
    © Copyright Vijos, cfc0146 beta, in 167.53793 ms

  • -1
    @ 2015-07-05 11:02:38

    0

    回复 yingjiangyu发表于2015-02-15 21:55
    打‘Wrong!’有50分。。

    0

    回复 东大微雕发表于2015-02-07 15:20
    这道题真是太好了。奇妙无穷。
    #include<iostream>
    #include<string.h>
    #include<stdio.h>
    using namespace std;
    int a[50005];
    int size;
    void go(){
    int i, j;
    int ans = 0;
    int dis[50005];
    memset(dis, 0, sizeof(dis));
    for (i = 1; i <= size; i++){
    int d = (a[i] - i + size) % size;
    dis[d]++;
    }
    for (i = 0; i < size; i++){
    if (ans < dis[i])
    ans = dis[i];
    }
    memset(dis, 0, sizeof(dis));
    for (i = 1; i <= size; i++){
    int d = (a[size+1-i]-i+size) % size;
    dis[d]++;
    }
    for (i = 0; i < size; i++){
    if (ans < dis[i])ans = dis[i];
    }
    cout << size-ans << endl;
    }
    int main(){
    freopen("in.txt", "r", stdin);
    int neibor[50005][2];
    int i;
    cin >> size;
    for (i = 1; i <= size; i++){
    scanf("%d%d",&neibor[i][0],& neibor[i][1]);
    }
    bool used[50005];
    memset(used, 0, sizeof(used));
    a[1] = 1;
    used[1] = true;
    for (i = 2; i <= size; i++){
    int last = a[i - 1];
    if (!used[neibor[last][0]]){
    a[i] = neibor[last][0];
    used[a[i]] = true;
    }
    else if (!used[neibor[last][1]]){
    a[i] = neibor[last][1];
    used[a[i]] = true;
    }
    else {
    cout << -1 << endl;
    return 0;
    }
    }

    if (neibor[1][0] != a[size] && neibor[1][1] != a[size]){
    cout << -1 << endl;
    return 0;
    }
    go();
    return 0;
    }

    0

    回复 3516发表于2014-07-30 08:59
    include<stdio.h>

    include<string.h>

    int data[50001][2],shi[50001],a[50001];
    int main()
    {
    int n,i,j,qian,hou; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d%d",&data[i][0],&data[i][1]); } a[1]=1;shi[a[1]]=1 for(i=2;i<=n;i++) { qian=data[a[i-1]][0]; hou=data[a[i-1]][1]; if(shi[qian]==0) { a[i]=qian; shi[qian]=1; } else if(shi[hou]==0) { a[i]=hou; shi[hou]=1; } else { printf("-1"); return 0; } } int temp=0,max=0; memset(shi,0,sizeof(shi)); for(i=1;i<=n;i++) { temp=(n+a[i]-i+1)%n; shi[temp]++; } for(i=0;i<n;i++) { if(max<shi[i]) { max=shi[i]; } } memset(shi,0,sizeof(shi)); for(i=1;i<=n;i++) { temp=(n+a[n-i+1]-i+1)%n; shi[temp]++;
    }
    for(i=0;i<n;i++)
    {
    if(max<shi[i])max=shi[i];
    }
    printf("%d",n-max);
    }

    0

    回复 S.Y.F发表于2013-08-31 14:04
    题解
    1111111129回复于2014-08-13 11:52
    orzorzorz

    0

    回复 S.Y.F发表于2013-07-29 16:55
    从10、到30、到100。。。。。。
    题解:http://blog.163.com/syf_light_feather/blog/static/223755067201362945326756/

    0

    回复 vcvycy发表于2013-06-30 00:56
    20 30 40 50 70 分都有~泪流满面.
    Accepted

    100
    772 2

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:55:05
    Wrong Answer

    70
    613 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:53:24
    Wrong Answer

    70
    686 2

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:45:35
    Wrong Answer

    70
    856 2

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:42:12
    Wrong Answer

    70
    803 2

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:37:26
    Wrong Answer

    70
    882 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:22:39
    Wrong Answer

    70
    1145 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:20:30
    Wrong Answer

    10
    733 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:11:30
    Wrong Answer

    50
    723 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:04:20
    Wrong Answer

    50
    781 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:55:49
    Wrong Answer

    40
    656 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:49:49
    Wrong Answer

    40
    758 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:44:00
    Time Exceeded

    30
    7160 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:38:22
    Time Exceeded

    20
    7135 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:35:08

    0

    回复 SEX丶Elope发表于2013-02-16 10:10
    点击查看程序源码+详细题解
    cuichen回复于2014-09-09 09:24
    怎么又是你??你有什么企图?骗访问量???垃圾!

    0

    回复 qyjubriskxp发表于2010-07-09 21:31
    再一次体会到c++流的悲剧,秒杀和3s原来只是输入方式的不同,杯具~~
    yuyilahanbao回复于2014-01-24 11:47
    从c转到c++第一次不AC(除去忘记把语言有c改为c++的)就是因为c++输入输出的问题
    从那次起,我的c++的输入都是用scanf和printf了
    因为
    保险
    安全
    我记不清cin是<<还是>>
    printf和scanf相对更灵活
    ....

    0

    回复 slm发表于2010-03-16 18:27
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    嘿嘿

    0

    回复 superyoi发表于2009-11-10 11:50

    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    superyoi killed p1008 with a headshot by awp

    0

    回复 200853349发表于2009-11-10 10:49
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    当我看到众位神牛打出“置换群”三个字后,我在黑书百度GOOGLE维基百科逛了得有一个半小时多然后回来AC了。。。

    思路和strini神牛的基本一样。

    0

    回复 sinb发表于2009-11-09 13:02
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    其实很简单,不要想复杂了,先是想办法构成,然后用置换群的方法即可ac。

    0

    回复 香蕉派发表于2009-11-06 11:29
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    虽然不懂什么叫置换群,但是思路还是很清晰的。。

    0

    回复 赏金神侠PPF发表于2009-11-05 11:45
    一星星纪念~

    0

    回复 strini发表于2009-10-30 22:11
    根据群论原理,任何置换群都可以分解为若干个循环节。显然,这道题目就是冲着这点来的。因为如果某循环的长度为L,那么本题中只需要代价为L的操作。注意,这里的L!=1,这是因为只有一个人的循环节不需要任何代价的操作。到这里才只能拿三十分,因为圈是可以旋转的,常规方法需要O(n^2)才能解决。不妨这里以编号为1的人为基准,定义每个人到自己应该所在位置的距离。距离不超过n-1。可以通过最大值来寻找能在自己位置上的最多的人数(因为距离为x的人在旋转x次后转到自己的位置上),那么在比较好的情况下,可以优化到O(n)。

    TIME: 1H
    SUBMIT:
    1 70 Error: 发现希望相邻是不精确的,于是改了个搜索方向。(以为题目给定的是按照左右方向,白书说过不能“假定”!)。
    2 90 Error: 终于明白要取两个搜索方向的最大值。
    3 Accepted.


    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 skykey发表于2009-10-29 17:58
    #include<iostream>
    using namespace std;
    int n;
    int a[50001],b[50001],c[50001];
    int aim[50001];
    void G_MAP()
    {
    bool mark[50001]={false};
    int p=1,r=1;
    while(p<=n)
    {
    aim[p]=r;mark[r]=true;p++;
    if(!mark[a[r]])r=a[r];
    else if(!mark[b[r]])r=b[r];
    else if(p<=n){cout<<-1;exit(0);}
    }
    }
    int COMPULATE()
    {
    int max=0;
    int t;
    int record[2][50001];
    for(int i=1;i<=n;i++)record[0][i]=record[1][i]=0;
    for(int i=1;i<=n;i++)
    {
    if((t=aim[i]-i)<0)t+=n;
    record[0][t]++;
    if(record[0][t]>max)max=record[0][t];
    if((t=aim[i]-(n+1-i))<0)t+=n;
    record[1][t]++;
    if (record[1][t]>max)max=record[1][t];
    }
    return max;
    }
    int main()
    {
    cin>>n;
    for(int i=1;i<=n;i++)
    {scanf("%d%d",&a[i],&b[i]);c[a[i]]++;c[b[i]]++;}
    for(int i=1;i<=n;i++)if(c[i]!=2){cout<<-1;return 0;}

    G_MAP();
    int T=COMPULATE();
    cout<<n-T;
    }

    0

    回复 song19931218发表于2009-10-27 20:11
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    考虑两种情形(貌似这两种情形很像,但又真的不同,后来才想起,在化学的手性碳原子那部分遇到过类似情况。。。)
    然后就是运用置换群的知识

    0

    回复 Aries_C发表于2009-10-25 08:24
    正反两遍...两遍...<幽幽的声音飘远..>

    不然就是70分啊...

    不看题解的情况下竟然自己想到了...

    记得以前老师给我们做过这题的..细节什么的现在做又忘记了..唉..

    0

    回复 国防安全员001发表于2009-10-21 22:00
    Flag   Accepted
    题号   P1008
    类型(?)   模拟
    通过   1701人
    提交   4835次
    通过率   35%
    难度   3

    题目表述有问题。。

    0

    回复 liubosen发表于2009-10-21 21:50
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    yaaaayyayayyayayayayayayayayayayayayayayayyaayayayayayayyaayayayay
    var
    n,max,i:longint;
    a,b,c,d:array[0..50001] of longint;
    begin
    readln(n);
    for i:=1 to n do
    readln(a[i],b[i]);
    c[1]:=1;
    c[2]:=a[1];
    for i:=3 to n do
    if c=a[c] then c[i]:=b[c]
    else
    if c=b[c] then c[i]:=a[c]
    else begin
    writeln(-1);
    halt
    end;
    if c[n]<>b[1] then
    begin
    writeln(-1);
    halt
    end;
    fillchar(d,sizeof(d),0);
    for i:=1 to n do
    inc(d[(c[i]-i+n)mod n]);
    for i:=0 to n-1 do
    if d[i]>max then max:=d[i];
    fillchar(d,sizeof(d),0);
    for i:=1 to n do
    inc(d[(c[i]+i-1)mod n]);
    for i:=0 to n-1 do
    if d[i]>max then max:=d[i];
    writeln(n-max);
    end.

    0

    回复 lishunzhi发表于2009-10-21 00:11
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    置换群,但建环是重点

    0

    回复 zebra发表于2009-10-03 09:48
    #include <iostream>
    #include <cassert>
    using namespace std;
    long N,seq[50001],p=1;
    class
    {
    private:
    long nbr[50001][3];
    bool flag[50001];
    bool isnbr(long v1,long v2)
    {
    for(int i=1;i<=nbr[v1][0];i++)
    if(nbr[v1][i]==v2)
    return true;
    return false;
    }
    public:
    bool AddE(long v1,long v2)
    {
    if(isnbr(v1,v2))
    return true;
    else
    if(nbr[v1][0]==2||nbr[v2][0]==2)
    return false;
    else
    {
    nbr[v1][++nbr[v1][0]]=v2;
    nbr[v2][++nbr[v2][0]]=v1;
    return true;
    }
    }
    void dfs(long i)
    {
    assert(!flag[i]);
    flag[i]=true,seq[p++]=i;
    for(int j=1;j<=nbr[i][0];j++)
    {
    if(!flag[nbr[i][j]])
    {
    dfs(nbr[i][j]);
    break;
    }
    }
    }
    }G;
    long solve()
    {
    long cnt1[50001]={0},cnt2[50001]={0},ans=0;
    for(int i=1,a,b;i<=N;i++){
    a=seq[i]-i;
    if(a<0) a+=N;
    b=seq[i]-(N+1-i);
    if(b<0) b+=N;
    if(++cnt1[a]>ans) ans=cnt1[a];
    if(++cnt2>ans) ans=cnt2;
    }
    return N-ans;
    }
    int main()
    {
    cin >> N;
    for(int i=1,nbr1,nbr2;i<=N;i++)
    {
    cin >> nbr1 >> nbr2;
    if(!G.AddE(i,nbr1)||!G.AddE(i,nbr2))
    {
    cout << -1 << endl;
    return 0;
    }
    }
    G.dfs(1);
    cout << solve() << endl;
    system("pause");
    return 0;
    }

    0

    回复 -117-Join发表于2009-09-18 21:29
    哪位大牛帮忙看看我错哪里了
    它只得90分
    program fire;
    type
    arr=record
    l,r:longint;
    end;
    var
    num:array[1..50000]of longint;
    a:array[1..50000]of arr;
    b:array[1..50000]of longint;
    i,k,j,n:longint;
    begin
    readln(n);
    for i:=1 to n do
    readln(a[i].l,a[i].r);
    b[1]:=1;
    b[n]:=a[1].l;
    if a[b[n]].l=b[1]then b[n-1]:=a[b[n]].r
    else b[n-1]:=a[b[n]].l;
    i:=n-1;
    b[2]:=a[1].r;
    j:=2;
    while j<=i do
    begin
    if b<>a[b[i]].l then b:=a[b[i]].l
    else b:=a[b[i]].r;
    dec(i);
    if b[j-1]<>a[b[j]].r then b[j+1]:=a[b[j]].r
    else b[j+1]:=a[b[j]].l;
    inc(j);
    end;
    for i:=2 to n-1 do
    if(b<>a[b[i]].r)and(b<>a[b[i]].l)or(b<>a[b[i]].r)and(b<>a[b[i]].l)then
    begin
    write(-1);
    halt
    end;
    if(b[n]<>a[b[1]].l)and(b[n]<>a[b[1]].r)or(b[2]<>a[b[1]].l)and(b[2]<>a[b[1]].r)or(b[1]<>a[b[n]].l)and(b[1]<>a[b[n]].r)or(b[n-1]<>a[b[n]].l)and(b[n-1]<>a[b[n]].r)then
    begin
    write(-1);
    halt
    end;
    num[0]:=0;
    for i:=1 to n do
    begin
    a[b[i]].l:=i;
    num[i]:=0;
    end;
    for i:=1 to n do
    if a[i].l-i>=0 then inc(num[a[i].l-i])
    else inc(num[a[i].l-i+n]);
    j:=0;
    for i:=0 to n do
    if num[i]>j then j:=num[i];
    write(n-j);
    end.
    写的有点长

    0

    回复 fs302发表于2009-09-17 20:13
    分析:学一个好思想:正难则反!由顺序到乱序我们很难快速找到,但是我们知道如何从乱序变为顺序!解决本题利用了组合数学中置换群的思想。

    从第一个人处断开,将圆环的问题转化为序列的问题。如果可以,求出目标序列。求出目标序列复杂度O(n).
    求出目标序列右移0至n-1位置时,不需要移动的人数。将目标序列反转,再求出目标序列右移0至n-1位置时,不需要移动的人数。求不需要移动的人数最大等价于求需要移动的人数最小。复杂度O(n)。
    更详细的说:
    引进“相对有序”这个概念,当两个人满足C[j]-C[i]==j-i时,两个相对有序。
    题目要求最小的总代价,但是我们可以考虑倒过来想,要求最小的总代价亦即求最多有多少人不用移动,亦即相对有序。
    然后我们引进一个辅助变量T=C-I,{C-I>=0},T=C[i]-I+N,{C[i]-I<0},那么这个T[i]有什么意义呢?我们知道初始状态的编号是1-N,而目标状态是C[1]-C[N],那么C-I便是从目标状态到初始状态顺时针所要移动的距离,那么如果那么T值相等的两个同学则是相对有序的,亦即不用移动,我们只要找出最大的T然后N-Max(T)就是得到的结果,但是这样还不够,因为刚刚那样只是顺时针所要移动的距离,我们还要计算逆时针的到的结果,从顺时针和逆时针中找到最大的T,然后N-Max(T)才能够是正确结果.

    0

    回复 maxint64发表于2009-09-01 21:33
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    先是物理大发了——以为 b1,b2...bm是连续的
    看了牛们的题解 一次ac :)

    0

    回复 柔情使者发表于2009-08-20 15:44
    第一遍做的时候没有看题解,自己测了好几遍总是60分,看了n多大牛的解释才恍然大悟,竟然要正反两遍!!!唉,幸亏咱有测试数据,否则我可就惨了...
    O(n)的求目标队列算法,都说是冒泡排序,我没看出来,倒是有点像。

    0

    回复 maxiem发表于2009-08-18 20:55
    物理自重啊,嘿嘿。
    注意要正反两遍哦~
    9MS?
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 9ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:9ms

    (好像那个冒泡是口胡,大家不要被那个蒙了

    program fire;
    var
    st:array [1..50000,1..2] of longint;
    k,final:array [0..50000] of longint;
    ex:array [1..50000] of boolean;
    p,max,i,n:longint;
    begin
    fillchar (st,sizeof(st),0);
    fillchar (ex,sizeof(ex),0);
    fillchar (final,sizeof(final),0);
    fillchar (k,sizeof(k),0);
    readln (n);
    for i:=1 to n do readln (st,st);
    final[1]:=1;p:=2;ex[1]:=true;
    for i:=1 to n do begin
    if ex[st[final[i],1]]=false then begin
    final[p]:=st[final[i],1];
    ex[st[final[i],1]]:=true;
    inc(p);
    end
    else if ex[st[final[i],2]]=false then begin
    final[p]:=st[final[i],2];
    ex[st[final[i],2]]:=true;
    inc(p);
    end;
    end;
    if p-1<>n then begin
    writeln (-1);
    halt;
    end;
    max:=0;
    for i:=1 to n do if final[i]>=i then inc(k[final[i]-i]) else inc(k[n-i+final[i]]);
    for i:=0 to n-1 do if k[i]>max then max:=k[i];
    fillchar (k,sizeof(k),0);
    for i:=n downto 1 do if final[i]>=n-i+1 then inc(k[final[i]-n+i-1]) else inc(k[final[i]+i-1]);
    for i:=0 to n -1 do if k[i]>max then max:=k[i];
    writeln (n-max);
    end.

    0

    回复 suning发表于2009-08-14 09:43
    啊呜~
    一年前误解了题意~
    一年后理解了题意~
    然后就是1次美妙的AC

    PS:[误]解[理]解~~~[物理]?

    0

    回复 fengwuliu发表于2009-08-13 17:20
    lgxcgd说的太对了!太感谢了5555

    0

    回复 Matt发表于2009-08-11 22:28
    NOIP也会考高等数学...

    由于原图是环,所以置换群可表示为一次循环。作差是个好方法。

    但求冒泡排序是怎么作的

    0

    回复 3830372发表于2009-08-11 21:28
    Flag   Accepted
    题号   P1008
    类型(?)   模拟
    通过   1504人
    提交   4282次
    通过率   35%
    难度   3

    提交 讨论 题解 状态

    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 尖端才子发表于2009-08-11 11:14
    纪念一下……第1500个AC……

    Flag    Accepted
    题号   P1008
    类型(?)   模拟
    通过   1500人
    提交   4274次
    通过率   35%
    难度   3

    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 SecretAgent发表于2009-08-10 14:02
    置换群是正解

    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 yangbei发表于2009-08-07 14:57
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 338ms
    ├ 测试数据 05:答案正确... 322ms
    ├ 测试数据 06:答案正确... 306ms
    ├ 测试数据 07:答案正确... 338ms
    ├ 测试数据 08:答案正确... 338ms
    ├ 测试数据 09:答案正确... 322ms

    ├ 测试数据 10:答案正确... 306ms

    Accepted 有效得分:100 有效耗时:2270ms

    算镜像时偷了点懒,不过也算一遍AC了

    0

    回复 ja_son发表于2009-08-06 15:44
    a:拆环成队,寻求目标队列。
    b:b1,b2...bm不是连续的,而且是任意的。只要有成立目标队列,与原来的队列相匹配就可以知道有多少(设为n个)需要移动位置,则代价就是n。
    c:目标队列有多种情况,可以反转,也可以左右移动。

    0

    回复 1s发表于2009-08-03 17:56

    如对本题有疑问可以参看我的题解:
    http://xujieqi.blog.hexun.com/35722312_d.html

    0

    回复 DMKaplony发表于2009-07-30 15:15
    当时的时间限制好像是2s。。有个题解说把1定为第一项然后进行冒泡排序。。不过这里是1s 啊。。。也行只有置换群了吧。

    0

    回复 xusc_2009发表于2009-07-28 14:30
    看不懂,只好搁浅
    什么时候想清楚了再做

    0

    回复 董发表于2009-07-24 19:11
    program p1008;
    var i,n,k,j,sum1,sum2,ans,max:longint;
       a,b,w,d,c:array[0..50005] of longint;

    begin
    readln(n);
    for i:=1 to n do
    readln(a[i],b[i]);
    w[1]:=1; w[2]:=a[w[1]];
    k:=1;

    repeat
    inc(k);
    if w[k-1]=a[w[k]] then w[k+1]:=b[w[k]]
      else if w[k-1]=b[w[k]] then w[k+1]:=a[w[k]]
       else begin
           writeln(-1);
           exit;
           end;
    until k=n;
    if w[n+1]<>w[1] then
           begin
           writeln(-1);
           exit;
           end;

    for i:=1 to n do
    begin
    a[i]:=w[i]-i;
    b[i]:=w[n-i+1]-i;
    if a[i]<0 then a[i]:=a[i]+n;
    if b[i]<0 then b[i]:=b[i]+n;
    inc(c[a[i]]);
    inc(d[b[i]]);
    end;
    for i:=0 to n-1 do
    begin
    if ans<c[i] then ans:=c[i];
    if ans<d[i] then ans:=d[i];
    end;
    writeln(n-ans);  
    end.

    0

    回复 我飞发表于2009-07-23 21:00
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 93狒狒发表于2009-07-23 20:59
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    秒杀......

    0

    回复 fjxmlhx发表于2009-07-22 13:15
    置换群,做2n次,顺时针和逆时针.
    对于一个置换,最小操作费用是所有循环长度的和.因此实际上是找出2n个置换中哪个置换循环长度为1的数量最多.

    0

    回复 340508965发表于2009-07-21 15:01
    ⊙﹏⊙b汗
    不知道的以为这是数学竞赛......
    ...
    我的数论与图论可以说脑袋里空白一片.........
    怎么办,我的竞赛啊
    ........

    算了 看了题解 大家写的
    总算弄懂这道题了
    先前以为b1,b2,b3..bm是连续的
    没想到是任意的!!!!!!!!!

    诶 叹悲歌未切 为撼奈何编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    总算AC了


    program p1008;
    var i,n,k,j,sum1,sum2,ans,max:longint;
    a,b,w,d,c:array[0..50005] of longint;

    begin
    readln(n);
    for i:=1 to n do
    readln(a[i],b[i]);
    w[1]:=1; w[2]:=a[w[1]];
    k:=1;

    repeat
    inc(k);
    if w[k-1]=a[w[k]] then w[k+1]:=b[w[k]]
    else if w[k-1]=b[w[k]] then w[k+1]:=a[w[k]]
    else begin
    writeln(-1);
    exit;
    end;
    until k=n;
    if w[n+1]<>w[1] then
    begin
    writeln(-1);
    exit;
    end;

    for i:=1 to n do
    begin
    a[i]:=w[i]-i;
    b[i]:=w[n-i+1]-i;
    if a[i]<0 then a[i]:=a[i]+n;
    if b[i]<0 then b[i]:=b[i]+n;
    inc(c[a[i]]);
    inc(d[b[i]]);
    end;
    for i:=0 to n-1 do
    begin
    if ans<c[i] then ans:=c[i];
    if ans<d[i] then ans:=d[i];
    end;
    writeln(n-ans);
    end.

    0

    回复 zsy90943发表于2009-07-18 00:51
    构造巧妙、、看来还是要学好数论和图论额、、、、

    0

    回复 POM无敌牛B发表于2009-07-16 11:47
    编译通过...
    ├ 测试数据 01:运行超时...
    ├ 测试数据 02:运行超时...
    ├ 测试数据 03:运行超时...
    ├ 测试数据 04:运行超时...
    ├ 测试数据 05:运行超时...
    ├ 测试数据 06:运行超时...
    ├ 测试数据 07:运行超时...
    ├ 测试数据 08:运行超时...
    ├ 测试数据 09:运行超时...

    ├ 测试数据 10:运行超时...

    Unaccepted 有效得分:0 有效耗时:0ms
    无奈 哪位哥哥救救我

    0

    回复 yxy发表于2009-06-16 18:16
    把置换解释成度为2图,真有才.
    求出序列,正反分别做一次差就行了.

    0

    回复 sxpeter发表于2009-06-14 16:56
    讲建环吧。数组w表示环,我用的是一种类似并查集的方法。
    begin
    read(n);
    for i:=1 to n do read(a[i],b[i]);
    t:=2;w[1]:=1;w[2]:=a[1];
    while true do begin
    if a[w[t]]<>w[t-1]then w[t+1]:=a[w[t]]//是否在左边
    else if b[w[t]]<>w[t-1]then w[t+1]:=b[w[t]]//是否在右边
    else begin writeln(-1);halt;end;//失败判断
    inc(t);
    if t>n then break;
    end;
    if w[n+1]<>w[1]then begin writeln(-1);halt;end;//本句一定要加!!!!!!
    end.

    0

    回复 lgxcgd发表于2009-05-17 20:24
    首先把这个圈看做一个图,每个同学看做一个顶点。因为要形成环,所以每个顶点的度必须为2。

    如果存在度数不为2的顶点,那么整个图无法构成一个环,即“无论怎么调整都不能符合每个同学的愿望”输出-1。

    如果是一个环,那么就遍历图,生成以第1个顶点为开头的序列。现在就要求出最小移动的代价。

    在理解题意所述的调整方式中,要注意实际上就是把M个在错误位置上的人移动到正确的位置上,代价为M。一次下令移动即可。

    假如生成的目标序列为1,5,3,2,4。我们现在就需要比较它和初始状态1,2,3,4,5,看有几个人离开了原来的位置。但这个序列实际代表的是一个环,而且方向正反有两种,就需要把初始序列正反分别转N次,和得到的序列比较,看其中最少有几个位置上的人编号不相同,就得到了我们要求的最小代价。

    上述方法有大量冗余。但可以发现转来转去不管怎么转,任意两个人之间的相对位置关系在这过程中都不会变。于是想到做差,如果差小于0则加上N。

    1 5 3 2 4

    - 1 2 3 4 5

    0 3 0 3 4
    这表示序列1,5,3,2,4不转动时1,3两个人在原来的位置上,转动3个位置后5和2两个人在原来的位置上,转动4个位置后只有4一个人会在原来的位置上。这就是说,1,5,3,2,4与1,2,3,4,5在旋转后最多有2个位置上的人编号相同,即最少有3个位置上的人编号不相同。同理要反转再求一次。

    记录每个不同的差值的个数,取其最大值P,即不调换次数最大的。结果N-P就是调换次数最小的。

    0

    回复 src250发表于2009-05-14 08:27

    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    切记:重新构图时一定要对数组清空!我的第一次只有50分,就是这个原因!

    0

    回复 love19960108发表于2009-04-26 17:59
    这题可以用C++这样做么??
    #include <iostream>
    #include <cassert>
    using namespace std;
    long N,seq[50001],p=1;
    class{
    private:
    long nbr[50001][3];
    bool flag[50001];
    bool isnbr(long v1,long v2){
    for(int i=1;i<=nbr[v1][0];i++)
    if(nbr[v1][i]==v2) return true;
    return false;
    }
    public:
    bool AddE(long v1,long v2){
    if(isnbr(v1,v2)) return true;
    else if(nbr[v1][0]==2||nbr[v2][0]==2) return false;
    else{
    nbr[v1][++nbr[v1][0]]=v2;
    nbr[v2][++nbr[v2][0]]=v1;
    return true;
    }
    }
    void dfs(long i){
    assert(!flag[i]);
    flag[i]=true,seq[p++]=i;
    for(int j=1;j<=nbr[i][0];j++){
    if(!flag[nbr[i][j]]){
    dfs(nbr[i][j]);
    break;
    }
    }
    }
    }G;
    long solve(){
    long cnt1[50001]={0},cnt2[50001]={0},ans=0;
    for(int i=1,a,b;i<=N;i++){
    a=seq[i]-i;
    if(a<0) a+=N;
    b=seq[i]-(N+1-i);
    if(b<0) b+=N;
    if(++cnt1[a]>ans) ans=cnt1[a];
    if(++cnt2>ans) ans=cnt2;
    }
    return N-ans;
    }
    int main(){
    cin >> N;
    for(int i=1,nbr1,nbr2;i<=N;i++){
    cin >> nbr1 >> nbr2;
    if(!G.AddE(i,nbr1)||!G.AddE(i,nbr2)){
    cout << -1 << endl;
    return 0;
    }
    }
    G.dfs(1);
    cout << solve() << endl;
    return 0;
    }

    0

    回复 voyagec2发表于2009-03-18 15:53
    难理解,不过算法很精妙

    0

    回复 pRoevollove发表于2009-02-25 23:49
    天,把(p[i]-i+n)mod n理所当然地打成了abs(p[i]-i)
    结果一直50分……还一直以为自己构造错了……

    ps 我可以过楼下的范例哦

    0

    回复 ufo172849z发表于2009-01-24 23:05
    ms楼下的程序不能处理这种反例(测试数据还是不够强啊)
    6
    2 3
    1 3
    1 2
    5 6
    4 6
    4 5
    应该输出-1的吧?因为是两个环

    var a,b:array[0..50000]of longint;
    c:array[0..50000,1..2]of longint;
    d:array[0..50000]of boolean;
    i,j,k,m,n,max:longint;
    can:boolean;

    begin
    readln(n);
    for i:=1 to n do
    readln(c,c);
    b[0]:=c[1,1]; b[n]:=c[1,1];
    fillchar(d,sizeof(d),0);
    k:=1;
    can:=true;
    for i:=1 to n-1 do
    begin
    if d[k] then can:=false;
    b[i]:=k; d[k]:=true;
    if b=c[k,1] then k:=c[k,2]
    else if b=c[k,2] then k:=c[k,1]
    else can:=false;
    if not can then break;
    end;
    if can then
    if b[n]<>k then can:=false;
    if can then
    begin
    max:=-1;
    fillchar(a,sizeof(a),0);
    for i:=1 to n do
    inc(a[(b[i]-i+n) mod n]);
    for i:=0 to n-1 do
    if a[i]>max then max:=a[i];
    fillchar(a,sizeof(a),0);
    for i:=1 to n do
    inc(a[(b[n-i+1]-i+n)mod n]);
    for i:=1 to n-1 do
    if a[i]>max then max:=a[i];
    writeln(n-max);
    end
    else
    writeln(-1);
    end.

    0

    回复 tangdongjian发表于2009-01-23 22:17
    我在做镜像时把原先max直接覆盖上了,注意

    0

    回复 永恒888发表于2009-10-26 22:50
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 tangkunjie发表于2009-06-04 19:50
    挺烦人的题目

    0

    回复 ykspeter发表于2008-11-13 20:32
    program fire(input,output);
    var
    n,i,j,k,max,v:longint;
    a:array[0..100000,1..2] of longint;
    b,c:array[0..100000] of longint;
    begin
    readln(n);
    for i:=1 to n do readln(a,a);
    for i:=1 to n do
       begin
        k:=0;
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if (k=4) or (k=3)
        then begin
           writeln('-1');
           exit
           end
       end;
    b[1]:=1;i:=2;k:=a[1,1];j:=1;
    repeat
      b[i]:=k;
      inc(i);
      v:=k;
      if a[k,1]<>j
      then k:=a[k,1]
      else k:=a[k,2];
      j:=v;
    until i=n+1;
    fillchar(c,sizeof(c),0);
    for i:=1 to n do inc(c[(b[i]-i+n)mod n]);
    for i:=0 to n-1 do
       if c[i]>max
       then max:=c[i];
    fillchar(c,sizeof(c),0);max:=0;
    for i:=1 to n do inc(c[(b[n-i+1]-i+n)mod n]);
    for i:=n-1 downto 0 do
       if c[i]>max
       then max:=c[i];
    writeln(n-max);
    end.

    0

    回复 getuojian发表于2008-11-10 13:38
    #include<stdio.h>
    #include<memory.h>

    const int maxn=50010;
    int n;
    int f[maxn][2];
    int goal[maxn];
    int ans=maxn;
    int hash[maxn];

    bool SET_ORI(){
    bool flag[maxn];
    memset(flag, true, sizeof(flag));
    goal[1]=1; flag[1]=false;
    for (int i=1; i<=n-1; i++){
    if (flag[f[goal[i]][0]]){
    goal=f[goal[i]][0];
    flag[f[goal[i]][0]]=false;
    continue;
    }
    if (flag[f[goal[i]][1]]){
    goal=f[goal[i]][1];
    flag[f[goal[i]][1]]=false;
    continue;
    }
    return false;
    }
    if ((goal[n]!=f[1][0]) && (goal[n]!=f[1][1]))
    return false;
    return true;
    }
    int SWAP(int i, int j){
    int t=goal[i];
    goal[i]=goal[j];
    goal[j]=t;
    return 0;
    }

    int min(int i, int j){
    return i>j?j:i;
    }
    int HASH(){
    for(int i=1; i<=n; i++)
    hash[i]=goal[i]-i+n;
    return 0;
    }

    int CALC(){
    int temp[maxn*2], back=0;
    memset(temp, 0, sizeof(temp));
    for (int i=1; i<=n; i++)
    temp[hash[i]%n]++;
    for (int i=1; i<=2*n-1; i++)
    if (temp[i] > back)
    back=temp[i];
    return back;
    }

    int main(){
    freopen("fire.in", "r", stdin);
    freopen("fire.out", "w", stdout);
    scanf("%d", &n);
    for (int i=1; i<=n; i++)
    scanf("%d %d", &f[i][0], &f[i][1]);
    if (!SET_ORI()){
    printf("-1");
    return 0;
    }
    //forward
    HASH();
    ans=min(ans, n-CALC());
    //backward
    for (int i=1; i<=n/2; i++)
    SWAP(i,n-i+1);
    HASH();
    ans=min(ans, n-CALC());

    printf("%d", ans);
    return 0;
    }

    0

    回复 IVORY发表于2008-11-06 10:46
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    CHEAT的...

    0

    回复 storey p发表于2008-11-05 14:19
    回447389831:
    exit换成halt

    0

    回复 FenXy发表于2008-11-04 08:28
    艺术p245

    0

    回复 hlq发表于2008-11-01 14:31
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms

    求不在位置上的人数
    a【i】 第i位上的同学编号
    for i:=1 to n do
    begin
    inc(b[(a[i]-i+n) mod n])
    end;
    max:=0;
    for i:=0 to n-1 do
    if b[i]>max then max:=b[i];
    fillchar(b,sizeof(b),0);
    for i:=1 to n do
    begin
    inc(b[(a[i]-(n-i+1)+n)mod n]);//对称
    end;
    for i:=0 to n-1 do
    if b[i]>max then max:=b[i];

    0

    回复 Will~骷髅发表于2008-10-30 21:37
    编译通过...
    ├ 测试数据 01:运行超时...
    ├ 测试数据 02:运行超时...
    ├ 测试数据 03:运行时错误...|错误号: -1073741819
    ├ 测试数据 04:运行时错误...|错误号: -1073741819
    ├ 测试数据 05:运行时错误...|错误号: -1073741819
    ├ 测试数据 06:运行时错误...|错误号: -1073741819
    ├ 测试数据 07:运行时错误...|错误号: -1073741819
    ├ 测试数据 08:运行时错误...|错误号: -1073741819
    ├ 测试数据 09:运行时错误...|错误号: -1073741819

    ├ 测试数据 10:运行时错误...|错误号: -1073741819

    Unaccepted 有效得分:0 有效耗时:0ms

    怎么会这样???

    0

    回复 悲伤逆流成河发表于2008-10-28 22:13
    #include <iostream>
    #include <fstream>
    using namespace std ;

    int hash[50001];
    int n , i , j , t , maxs(0) ;

    inline void HASH ( int e[] )
    {
    for ( i = 1 ; i <= n ; i++ )
    {
    e[i] -= i ;
    if ( e[i] < 0 ) e[i] += n ;
    hash[e[i]]++ ;
    }
    for ( i = 0 ; i < 50001 ; i++ )
    if ( maxs < hash[i] ) maxs = hash[i] ;
    }

    int main(){
    ifstream fin ("fire.in") ;
    ofstream fout ("fire.out") ;

    fin >> n ;
    int e[n+1] , h[n+1][2] , e2[n+1];
    bool f[n+1] ;
    for ( i = 1 ; i <= n ; i++ )
    {
    f[i] = false ;
    fin >> h[i][0] >> h[i][1] ;
    }
    e[1] = 1 ;
    f[1] = true ;
    for ( i = 2 ; i <= n ; i++ )
    {
    if ( e < 0 ) { fout << -1 << endl ; exit(0) ; }
    if ( !f [ h[ e ][0] ] ) e[i] = h[ e ][0] ;
    if ( !f [ h[ e ][1] ] ) e[i] = h[ e ][1] ;
    f[ e[i] ] = true ;
    }
    for ( i = 1 , j = n ; i <= n ; i++,j-- ) e2[j] = e[i] ;
    HASH ( e ) ;
    memset ( hash , 0 , sizeof ( hash ) ) ;
    HASH ( e2 ) ;
    fout << n - maxs << endl ;
    }

    0

    回复 evelynhe发表于2008-10-26 16:31
    “置换群思想...今天刚明白...

    先构造新数列(要构造两次,否则只有70分),然后向右计算相对位置差,然后累加记录数组,然后用N减去相对位置差累加值最大的,就是答案... ”

    这是真的

    0

    回复 true1023发表于2008-10-25 09:32
    置换群的基本概念
    利用原序列和目标序列每个元素的绝对位置差来求出原序列每个元素对于目标序列的相对位置,找相对位置相同的最多的元素数,用总元素数减去它即为结果。

    0

    回复 447389831发表于2008-10-21 09:45
    program fire(input,output);
    var
    n,i,j,k,max,v:longint;
    a:array[0..100000,1..2] of longint;
    b,c:array[0..100000] of longint;
    begin
    readln(n);
    for i:=1 to n do readln(a,a);
    for i:=1 to n do
       begin
        k:=0;
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if (k=4) or (k=3)
        then begin
           writeln('-1');
           exit
           end
       end;
    b[1]:=1;i:=2;k:=a[1,1];j:=1;
    repeat
      b[i]:=k;
      inc(i);
      v:=k;
      if a[k,1]<>j
      then k:=a[k,1]
      else k:=a[k,2];
      j:=v;
    until i=n+1;
    fillchar(c,sizeof(c),0);
    for i:=1 to n do inc(c[(b[i]-i+n)mod n]);
    for i:=0 to n-1 do
       if c[i]>max
       then max:=c[i];
    fillchar(c,sizeof(c),0);max:=0;
    for i:=1 to n do inc(c[(b[n-i+1]-i+n)mod n]);
    for i:=n-1 downto 0 do
       if c[i]>max
       then max:=c[i];
    writeln(n-max);
    end.
    90 分,牛人门帮看下把

    0

    回复 cnfnje1发表于2008-10-17 18:12
    置换群.....是什么?
    readln(n);
    for i:=1 to n do readln(a[i],b[i]);
    c[1]:=1; c[2]:=a[1];
    for i:=3 to n do if c=a[c] then c[i]:=b[c]
    else if c=b[c] then c[i]:=a[c]
    else begin writeln(-1); halt end;
    if c[n]<>b[1] then begin writeln(-1); halt end;
    fillchar(d,sizeof(d),0);
    for i:=1 to n do inc(d[(c[i]-i+n)mod n]);
    for i:=0 to n-1 do if d[i]>m then m:=d[i];
    fillchar(d,sizeof(d),0);
    for i:=1 to n do inc(d[(c[i]+i-1)mod n]);
    for i:=0 to n-1 do if d[i]>m then m:=d[i];
    writeln(n-m);
    是么?

    0

    回复 lyrics发表于2008-10-12 19:55
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    技巧性比较强吧,楼下不必构造2次,计算时从头至尾算一次,再倒过来算一次就行了

    0

    回复 LV.唱响发表于2008-10-05 08:38
    置换群思想...今天刚明白...

    先构造新数列(要构造两次,否则只有70分),然后向右计算相对位置差,然后累加记录数组,然后用N减去相对位置差累加值最大的,就是答案...

    0

    回复 宇智波带波斯猫发表于2008-10-05 08:33
    Flag   Accepted
    题号   P1008
    类型(?)   其它
    通过   1065人
    提交   3000次
    通过率   35%
    难度   3

    第3000个提交的

    0

    回复 鸳鸯羡发表于2008-09-28 18:19
    #include <iostream>
    using namespace std ;

    int hash[50001];
    int n , i , j , t , maxs(0) ;

    inline void HASH ( int e[] )
    {
    for ( i = 1 ; i <= n ; i++ )
    {
    e[i] -= i ;
    if ( e[i] < 0 ) e[i] += n ;
    hash[e[i]]++ ;
    }
    for ( i = 0 ; i < 50001 ; i++ )
    if ( maxs < hash[i] ) maxs = hash[i] ;
    }

    int main(){
    cin >> n ;
    int e[n+1] , h[n+1][2] , e2[n+1];
    bool f[n+1] ;
    for ( i = 1 ; i <= n ; i++ )
    {
    f[i] = false ;
    cin >> h[i][0] >> h[i][1] ;
    }
    e[1] = 1 ;
    f[1] = true ;
    for ( i = 2 ; i <= n ; i++ )
    {
    if ( e < 0 ) { cout << -1 << endl ; exit(0) ; }
    if ( !f [ h[ e ][0] ] ) e[i] = h[ e ][0] ;
    if ( !f [ h[ e ][1] ] ) e[i] = h[ e ][1] ;
    f[ e[i] ] = true ;
    }
    for ( i = 1 , j = n ; i <= n ; i++,j-- ) e2[j] = e[i] ;
    HASH ( e ) ;
    memset ( hash , 0 , sizeof ( hash ) ) ;
    HASH ( e2 ) ;
    cout << n - maxs << endl ;
    }

    80分

    0

    回复 月光疾风发表于2008-09-25 13:03
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    纪念我第200次提交!过第79题。。。。

    0

    回复 ghostplant发表于2008-09-20 19:48
    #include <iostream>
    #include <fstream>
    #include <cassert>
    using namespace std;
    long N,seq[50001],p=1;
    class{
    private:
    long nbr[50001][3];
    bool flag[50001];
    bool isnbr(long v1,long v2){
    for(int i=1;i<=nbr[v1][0];i++)
    if(nbr[v1][i]==v2) return true;
    return false;
    }
    public:
    bool AddE(long v1,long v2){
    if(isnbr(v1,v2)) return true;
    else if(nbr[v1][0]==2||nbr[v2][0]==2) return false;
    else{
    nbr[v1][++nbr[v1][0]]=v2;
    nbr[v2][++nbr[v2][0]]=v1;
    return true;
    }
    }
    void dfs(long i){
    assert(!flag[i]);
    flag[i]=true,seq[p++]=i;
    for(int j=1;j<=nbr[i][0];j++){
    if(!flag[nbr[i][j]]){
    dfs(nbr[i][j]);
    break;
    }
    }
    }
    }G;
    long solve(void){
    long cnt1[50001]={0},cnt2[50001]={0},ans=0;
    for(int i=1,a,b;i<=N;i++){
    a=seq[i]-i;
    if(a<0) a+=N;
    b=seq[i]-(N+1-i);
    if(b<0) b+=N;
    if(++cnt1[a]>ans) ans=cnt1[a];
    if(++cnt2>ans) ans=cnt2;
    }
    return N-ans;
    }
    int main(){
    cin >> N;
    for(int i=1,nbr1,nbr2;i<=N;i++){
    cin >> nbr1 >> nbr2;
    if(!G.AddE(i,nbr1)||!G.AddE(i,nbr2)){
    cout << -1 << endl;
    return 0;
    }
    }
    G.dfs(1);
    cout << solve() << endl;
    return 0;
    }

    0

    回复 zzh19950802发表于2008-09-17 19:29
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案错误... ├ 标准行输出
     ├ 错误行输出
    ├ 测试数据 05:答案错误... ├ 标准行输出
     ├ 错误行输出
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 462ms
    ├ 测试数据 08:答案正确... 369ms
    ├ 测试数据 09:答案正确... 384ms
    ├ 测试数据 10:答案错误...程序输出比正确答案长
    为什么我的程序不对?
    #include <iostream>
    using namespace std;
    #define MAXN 50000
    int man[MAXN+2][2];
    int cercle[MAXN+2]={0,1};
    int used[MAXN+2]={0};
    int reduce[2][MAXN+2]={0};
    int n;
    int main()
    {
    long i,p,q=1,t;
    int max=0;
    cin>>n;
    for (i=1;i<=n;i++) cin>>man[i][0]>>man[i][1];
    p=man[q][1];
    for (i=2;i<=n+1;i++)
    {
    if (man[q][1]==p)
    {
    p=q;
    q=man[q][0];
    }
    else
    {
    if(man[q][0]!=p) break;
    p=q;
    q=man[q][1];
    }
    if(used[q]) break;
    else used[q]=1;
    cercle[i]=q;
    }
    if (i<=n+1) cout<<-1;
    else
    {
    for (i=1;i<=n;i++)
    {
    if((t=cercle[i]-i)<0) t+=n;
    reduce[0][t]++;
    if (reduce[0][t]>max) max=reduce[0][t];
    if ((t=cercle[i]-n+i-1)<0) t+=n;
    if (reduce[1][t]>max) max=reduce[1][t];
    }
    cout<<n-max;
    }
    return 0;
    }

    0

    回复 liaorc发表于2008-09-16 17:56
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 cxy450090074发表于2008-09-04 13:34
    oh no

    0

    回复 Lost.G发表于2008-08-22 15:49
    我在想``怎么样才能不看错这题呢

    0

    回复 bonism发表于2008-08-14 21:30
    时间复杂度O(N)。。。

    原来我一直把题意理解错。。。囧!!。。

    关于“置换群”,请看LRJ的《算法艺术与信息学竞赛》P245那一小节,还是比较好理解的。

    0

    回复 lemon_cn发表于2008-08-08 15:55
    热烈庆祝用pascal AC的第二题~
    p.s.我是C++的~~

    0

    回复 oipn4e2发表于2008-08-05 21:36
    解决效率不高,但AC了。

    0

    回复 notblack发表于2008-08-01 09:17
    用距离来分类,统计在原位的最大人数,奇怪的是
    b[1]:=1;
    b[2]:=a[1,1];
    b[n]:=a[1,2];

    建环的时候,上面的改成
    b[1]:=1;
    b[2]:=a[1,2];
    b[n]:=a[1,1];

    最后一个点却过不了,太奇怪了.

    0

    回复 332404521发表于2008-07-14 13:53
    对于初三刚刚中考完的我,要理解这题的意思是万万不能的。。。
    看题解我知道了应该怎么做,但那不是我的,所以不做了。。。
    哪天能证明出来那啥再来做

    0

    回复 Sheeta发表于2007-11-14 15:45
    好简单啊
    直接贪啊
    (P.S.置换群?什么东东...)

    0

    回复 mingyueyucai发表于2007-11-09 21:22
    我代码写了老长老长,结果还是只过了8个点,有没有搞错?
    我想请问一下,我和大家的一样,先排列出目标状态.然后确定初始状态时使得最多的人在目标位置上,然后交换.但是得到的答案总是偏大一点.
    然后我又把所有可以使最多的人在原位目标位置上的可能都尝试了一编(包括正反两个目标状态),结果还是只能过8个点,有2个点死都过不了!
    我的算法有什么问题吗?

    0

    回复 luanjiyang发表于2007-11-08 08:44
    很委琐的说 我提交了8遍。。
    0→0→10→10→10→10→70→AC

    • -||

    0

    回复 lonelycorn发表于2007-11-05 23:31
    数论……好底歇的东西。

    0

    回复 gamejifan发表于2007-11-04 11:15
    这题的叙述,让我误会了一年多。tzkq……3q..要早知道是这种意思早就ac了这题。。显然没什么大意思,看过组合数学或者学过群论的都懂。。ms跟polya计数法那个循环的意思。。

    写的时候竟然因为交换的时候写错一个字母wa。我汗。

    0

    回复 Alexandria发表于2007-11-01 13:33
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    好强大的题啊,不看题解还真不会!

    0

    回复 clfhaha1234发表于2007-10-30 18:09
    请问什么是置换群啊?可以讲讲吗?………………

    0

    回复 rleepas发表于2007-10-30 13:18
    楼下都是正解?
    ......

    0

    回复 Ice_Msk发表于2007-10-18 20:35
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    什么是置换群?不知道。。。照样过。。。。

    0

    回复 junlonely发表于2007-10-18 20:13
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 江南不才发表于2007-10-11 16:19
    排序法这里会超时~~~~~
    比赛的时间是2S~~
    这里是1S~~
    (_)

    0

    回复 秒杀群众发表于2007-10-10 17:05
    居然是置换群。。。
    对了。。。什么是置换群...
    上网查啊!!!

    0

    回复 southstarj1发表于2007-10-02 18:50
    思想:
    置换群。(相关知识自己查)
    对于一组数据,按各人的意愿排出一个序列,
    如果无法排出,就输出-1。
    再将环状序列变成链状,则这个目标序列为一个置换群,
    与原序列(按1到n的一列)满足:
    交换的最少人数等于目标序列与原序列不重合的人数。
    因为总共有2n个目标序列(正反各n种),都算一遍就行了。

    步骤:
    1. 读入数据;
    2. 构造一个目标序列;
    3. 统计该序列中元素位置与该元素在原序列位置的差值(同一方向)为i{i ∈ [0, n)}的元素个数;
    4. 将该序列的反序统计一遍;
    5. 从这些数据中选取一个最大的值max;
    6. 输出n - max;

    注意:
    构造目标序列时判断能否构造的条件;
    统计一次差值的复杂度是O(n);
    统计差值的目的是求与原序列最多的重合人数;

    0

    回复 wangjin5发表于2007-09-19 22:38
    好经典的题奥
    确实有难度

    0

    回复 the_melody发表于2007-09-03 17:58
    Accepted 有效得分:100 有效耗时:0ms
    好经典的题奥

    0

    回复 richardxx发表于2007-08-22 17:36
    下面程序是错的,不好意思,弄错地方了....

    0

    回复 sm-star发表于2007-08-21 15:18
    题目所求就是每次进行连续交换的人数总和,这样,一个看似复杂的题目就变的异常的简单了!

    0

    回复 wasyyyy发表于2007-08-11 02:05
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    HOHO~~~看讨论的时候看到有人提到‘置换群’这个东西,突然想起来我刚买的一本组合数学上有这么一块东西,就拿过来看了。。。。
    然后就出现上面的东西了。。。。置换群,本来想求轮换的,发现轮换比较多,还是找不参与交换的比较好记。。。。

    优化的方法。。。我看了下好象不只一个人讲过了。。。而且似乎我跟他们的都一样(没仔细看)所以就不说了。。。效率是O(n)的。。不用建环。

    0

    回复 angieqiu发表于2007-08-10 22:49
    怎么判断建环失败啊?我的程序虽然AC但总觉得方法很傻

    0

    回复 梦ぁ逍遥发表于2007-07-17 13:45
    想到了用t[i]=b[i]-i表示环
    却没想到镜像..

    十分感谢visister
    让我从90分中挣扎出来...

    0

    回复 visister发表于2007-06-01 00:12
    首先明显地可以知道我们需要对于目标状态建立出一个环。如果无法建立这个环,那么结果一定是-1,当建立好环以后可以知道最小移动代价一定等于最少的不在目标位置上的人数。那么我们可以对目标环进行顺时针旋转1~n-1之中任意一个,答案就一定等于旋转中的不在自己位置上的人数最少的那样的环的状态。但是对于50000的数据,我们如果要将环旋转1~n-1次,那么总共加上判断不在自己位置上的人数时间复杂度为O(n^2),显然在限定时间内是无法出解的。因此我们进行逆向思维:不在自己位置上最少的人数就一定会等于总人数减去在自己位置上最多的人数(仔细想想),那么我们就将该问题转化为了求在自己的位置上最多的人数,这样一来,我们对初始目标环中每一个位置进行判断需要旋转多少次可以回到自己位置上,每一个人的选择都将映射到[0..n-1]的数组中,选取当中最大的情况就为所求,但是考虑到环可以反转,那么我们还需要将环再求一次镜像,就可以得到初始目标需要旋转多少次可以得到在自己位置上最多的人数的环的状态,最后通过总的人数减去它即为问题所求,时间复杂度为O(n);

    0

    回复 pyh119发表于2006-11-16 20:11
    哪个人不小心失火了找我啊!!!

    PS:我是安徽省芜湖市119接线员....

    0

    回复 maomingming发表于2006-11-06 18:40
    考虑旋转后最多可能重合的情况,另要注意圈可以反过来

    0

    回复 qian5发表于2006-09-30 21:35
    直接输出‘-1’有一个点过

    0

    回复 BambooLeaf发表于2006-09-26 18:17
    见过的最牛最简单的方法……
    将此题转换为冒泡排序,记录下所有交换的次数和两数间的距离,加上就行了……—__—|||
    具体是这样的,我们反向思维,本来是要求一个有序数列求出成为无序数列的代价,现在我们把无序数列(即目标数列)进行冒泡排序,然后……就是这样……
    看完之后,偶巨汗……

    0

    回复 xcjzj发表于2006-09-26 17:18
    每组数据确定两组相对位置关系,并且这两组互为镜像。
    对于某一种排列方式,不在需要位置上的人数即为当前状态到目标状态的最小代价。
    先找出其中一种排列方式。由于目标状态可以通过旋转而使得部分人的变化次数减少,所以找出每个人通过某一固定方向旋转到达目标位置的旋转次数。找到某一次数,使得拥有这个次数的人数最多。那么,通过旋转这一最多人拥有的次数,即可使得尽可能多的人不通过交换直接到达目标位置。于是,不拥有这一旋转次数的人数即为这一状态下的最小代价。
    然后,用现在的目标状态找出其镜像状态,并且用上述方法再找一遍最小代价,与前面的结果比较,较小值即为答案。
    另外,题目中会出现一些无解的情况:
    1.某个人被“要”的次数多于两次,也就是说有多于两个的人想要与他(她)邻座,那么无解。
    2.根据要求得出的目标状态为多于一个的环,也无解。

    0

    回复 东邪歪刀发表于2006-07-28 17:27
    提交了若干次……残念……

    0

    回复 sugar发表于2006-07-28 16:26
    这题比赛时真有人ac?
    真不好想
    为什么得开longint啊?

    0

    回复 晶星发表于2006-07-25 13:29
    排列本质不同的只有二种 正着和反着的
    检验几个人不在位置上用数学方法:)模拟法超时的

    0

    回复 tzkq发表于2006-07-23 04:37
    注意别误解题意 b1,b2....bm并不指连续位置上的数

    0

    回复 Coldwings发表于2006-01-26 09:21
    可以用群论证明:如果有k个人不在自己的位置上,那么要且仅要k的代价,即可使这些人归位

    剩下的..很简单了吧...

    0

    回复 lemon_cn发表于2008-08-08 15:55
    热烈庆祝用pascal AC的第二题~
    p.s.我是C++的~~
    0

    回复 yingjiangyu发表于2015-02-15 21:55
    打‘Wrong!’有50分。。

    0

    回复 东大微雕发表于2015-02-07 15:20
    这道题真是太好了。奇妙无穷。
    #include<iostream>
    #include<string.h>
    #include<stdio.h>
    using namespace std;
    int a[50005];
    int size;
    void go(){
    int i, j;
    int ans = 0;
    int dis[50005];
    memset(dis, 0, sizeof(dis));
    for (i = 1; i <= size; i++){
    int d = (a[i] - i + size) % size;
    dis[d]++;
    }
    for (i = 0; i < size; i++){
    if (ans < dis[i])
    ans = dis[i];
    }
    memset(dis, 0, sizeof(dis));
    for (i = 1; i <= size; i++){
    int d = (a[size+1-i]-i+size) % size;
    dis[d]++;
    }
    for (i = 0; i < size; i++){
    if (ans < dis[i])ans = dis[i];
    }
    cout << size-ans << endl;
    }
    int main(){
    freopen("in.txt", "r", stdin);
    int neibor[50005][2];
    int i;
    cin >> size;
    for (i = 1; i <= size; i++){
    scanf("%d%d",&neibor[i][0],& neibor[i][1]);
    }
    bool used[50005];
    memset(used, 0, sizeof(used));
    a[1] = 1;
    used[1] = true;
    for (i = 2; i <= size; i++){
    int last = a[i - 1];
    if (!used[neibor[last][0]]){
    a[i] = neibor[last][0];
    used[a[i]] = true;
    }
    else if (!used[neibor[last][1]]){
    a[i] = neibor[last][1];
    used[a[i]] = true;
    }
    else {
    cout << -1 << endl;
    return 0;
    }
    }

    if (neibor[1][0] != a[size] && neibor[1][1] != a[size]){
    cout << -1 << endl;
    return 0;
    }
    go();
    return 0;
    }

    0

    回复 3516发表于2014-07-30 08:59
    include<stdio.h>

    include<string.h>

    int data[50001][2],shi[50001],a[50001];
    int main()
    {
    int n,i,j,qian,hou; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d%d",&data[i][0],&data[i][1]); } a[1]=1;shi[a[1]]=1 for(i=2;i<=n;i++) { qian=data[a[i-1]][0]; hou=data[a[i-1]][1]; if(shi[qian]==0) { a[i]=qian; shi[qian]=1; } else if(shi[hou]==0) { a[i]=hou; shi[hou]=1; } else { printf("-1"); return 0; } } int temp=0,max=0; memset(shi,0,sizeof(shi)); for(i=1;i<=n;i++) { temp=(n+a[i]-i+1)%n; shi[temp]++; } for(i=0;i<n;i++) { if(max<shi[i]) { max=shi[i]; } } memset(shi,0,sizeof(shi)); for(i=1;i<=n;i++) { temp=(n+a[n-i+1]-i+1)%n; shi[temp]++;
    }
    for(i=0;i<n;i++)
    {
    if(max<shi[i])max=shi[i];
    }
    printf("%d",n-max);
    }

    0

    回复 S.Y.F发表于2013-08-31 14:04
    题解
    1111111129回复于2014-08-13 11:52
    orzorzorz

    0

    回复 S.Y.F发表于2013-07-29 16:55
    从10、到30、到100。。。。。。
    题解:http://blog.163.com/syf_light_feather/blog/static/223755067201362945326756/

    0

    回复 vcvycy发表于2013-06-30 00:56
    20 30 40 50 70 分都有~泪流满面.
    Accepted

    100
    772 2

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:55:05
    Wrong Answer

    70
    613 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:53:24
    Wrong Answer

    70
    686 2

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:45:35
    Wrong Answer

    70
    856 2

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:42:12
    Wrong Answer

    70
    803 2

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:37:26
    Wrong Answer

    70
    882 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:22:39
    Wrong Answer

    70
    1145 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:20:30
    Wrong Answer

    10
    733 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:11:30
    Wrong Answer

    50
    723 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:04:20
    Wrong Answer

    50
    781 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:55:49
    Wrong Answer

    40
    656 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:49:49
    Wrong Answer

    40
    758 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:44:00
    Time Exceeded

    30
    7160 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:38:22
    Time Exceeded

    20
    7135 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:35:08

    0

    回复 SEX丶Elope发表于2013-02-16 10:10
    点击查看程序源码+详细题解
    cuichen回复于2014-09-09 09:24
    怎么又是你??你有什么企图?骗访问量???垃圾!

    0

    回复 qyjubriskxp发表于2010-07-09 21:31
    再一次体会到c++流的悲剧,秒杀和3s原来只是输入方式的不同,杯具~~
    yuyilahanbao回复于2014-01-24 11:47
    从c转到c++第一次不AC(除去忘记把语言有c改为c++的)就是因为c++输入输出的问题
    从那次起,我的c++的输入都是用scanf和printf了
    因为
    保险
    安全
    我记不清cin是<<还是>>
    printf和scanf相对更灵活
    ....

    0

    回复 slm发表于2010-03-16 18:27
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    嘿嘿

    0

    回复 superyoi发表于2009-11-10 11:50

    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    superyoi killed p1008 with a headshot by awp

    0

    回复 200853349发表于2009-11-10 10:49
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    当我看到众位神牛打出“置换群”三个字后,我在黑书百度GOOGLE维基百科逛了得有一个半小时多然后回来AC了。。。

    思路和strini神牛的基本一样。

    0

    回复 sinb发表于2009-11-09 13:02
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    其实很简单,不要想复杂了,先是想办法构成,然后用置换群的方法即可ac。

    0

    回复 香蕉派发表于2009-11-06 11:29
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    虽然不懂什么叫置换群,但是思路还是很清晰的。。

    0

    回复 赏金神侠PPF发表于2009-11-05 11:45
    一星星纪念~

    0

    回复 strini发表于2009-10-30 22:11
    根据群论原理,任何置换群都可以分解为若干个循环节。显然,这道题目就是冲着这点来的。因为如果某循环的长度为L,那么本题中只需要代价为L的操作。注意,这里的L!=1,这是因为只有一个人的循环节不需要任何代价的操作。到这里才只能拿三十分,因为圈是可以旋转的,常规方法需要O(n^2)才能解决。不妨这里以编号为1的人为基准,定义每个人到自己应该所在位置的距离。距离不超过n-1。可以通过最大值来寻找能在自己位置上的最多的人数(因为距离为x的人在旋转x次后转到自己的位置上),那么在比较好的情况下,可以优化到O(n)。

    TIME: 1H
    SUBMIT:
    1 70 Error: 发现希望相邻是不精确的,于是改了个搜索方向。(以为题目给定的是按照左右方向,白书说过不能“假定”!)。
    2 90 Error: 终于明白要取两个搜索方向的最大值。
    3 Accepted.


    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 skykey发表于2009-10-29 17:58
    #include<iostream>
    using namespace std;
    int n;
    int a[50001],b[50001],c[50001];
    int aim[50001];
    void G_MAP()
    {
    bool mark[50001]={false};
    int p=1,r=1;
    while(p<=n)
    {
    aim[p]=r;mark[r]=true;p++;
    if(!mark[a[r]])r=a[r];
    else if(!mark[b[r]])r=b[r];
    else if(p<=n){cout<<-1;exit(0);}
    }
    }
    int COMPULATE()
    {
    int max=0;
    int t;
    int record[2][50001];
    for(int i=1;i<=n;i++)record[0][i]=record[1][i]=0;
    for(int i=1;i<=n;i++)
    {
    if((t=aim[i]-i)<0)t+=n;
    record[0][t]++;
    if(record[0][t]>max)max=record[0][t];
    if((t=aim[i]-(n+1-i))<0)t+=n;
    record[1][t]++;
    if (record[1][t]>max)max=record[1][t];
    }
    return max;
    }
    int main()
    {
    cin>>n;
    for(int i=1;i<=n;i++)
    {scanf("%d%d",&a[i],&b[i]);c[a[i]]++;c[b[i]]++;}
    for(int i=1;i<=n;i++)if(c[i]!=2){cout<<-1;return 0;}

    G_MAP();
    int T=COMPULATE();
    cout<<n-T;
    }

    0

    回复 song19931218发表于2009-10-27 20:11
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    考虑两种情形(貌似这两种情形很像,但又真的不同,后来才想起,在化学的手性碳原子那部分遇到过类似情况。。。)
    然后就是运用置换群的知识

    0

    回复 Aries_C发表于2009-10-25 08:24
    正反两遍...两遍...<幽幽的声音飘远..>

    不然就是70分啊...

    不看题解的情况下竟然自己想到了...

    记得以前老师给我们做过这题的..细节什么的现在做又忘记了..唉..

    0

    回复 国防安全员001发表于2009-10-21 22:00
    Flag   Accepted
    题号   P1008
    类型(?)   模拟
    通过   1701人
    提交   4835次
    通过率   35%
    难度   3

    题目表述有问题。。

    0

    回复 liubosen发表于2009-10-21 21:50
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    yaaaayyayayyayayayayayayayayayayayayayayayyaayayayayayayyaayayayay
    var
    n,max,i:longint;
    a,b,c,d:array[0..50001] of longint;
    begin
    readln(n);
    for i:=1 to n do
    readln(a[i],b[i]);
    c[1]:=1;
    c[2]:=a[1];
    for i:=3 to n do
    if c=a[c] then c[i]:=b[c]
    else
    if c=b[c] then c[i]:=a[c]
    else begin
    writeln(-1);
    halt
    end;
    if c[n]<>b[1] then
    begin
    writeln(-1);
    halt
    end;
    fillchar(d,sizeof(d),0);
    for i:=1 to n do
    inc(d[(c[i]-i+n)mod n]);
    for i:=0 to n-1 do
    if d[i]>max then max:=d[i];
    fillchar(d,sizeof(d),0);
    for i:=1 to n do
    inc(d[(c[i]+i-1)mod n]);
    for i:=0 to n-1 do
    if d[i]>max then max:=d[i];
    writeln(n-max);
    end.

    0

    回复 lishunzhi发表于2009-10-21 00:11
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    置换群,但建环是重点

    0

    回复 zebra发表于2009-10-03 09:48
    #include <iostream>
    #include <cassert>
    using namespace std;
    long N,seq[50001],p=1;
    class
    {
    private:
    long nbr[50001][3];
    bool flag[50001];
    bool isnbr(long v1,long v2)
    {
    for(int i=1;i<=nbr[v1][0];i++)
    if(nbr[v1][i]==v2)
    return true;
    return false;
    }
    public:
    bool AddE(long v1,long v2)
    {
    if(isnbr(v1,v2))
    return true;
    else
    if(nbr[v1][0]==2||nbr[v2][0]==2)
    return false;
    else
    {
    nbr[v1][++nbr[v1][0]]=v2;
    nbr[v2][++nbr[v2][0]]=v1;
    return true;
    }
    }
    void dfs(long i)
    {
    assert(!flag[i]);
    flag[i]=true,seq[p++]=i;
    for(int j=1;j<=nbr[i][0];j++)
    {
    if(!flag[nbr[i][j]])
    {
    dfs(nbr[i][j]);
    break;
    }
    }
    }
    }G;
    long solve()
    {
    long cnt1[50001]={0},cnt2[50001]={0},ans=0;
    for(int i=1,a,b;i<=N;i++){
    a=seq[i]-i;
    if(a<0) a+=N;
    b=seq[i]-(N+1-i);
    if(b<0) b+=N;
    if(++cnt1[a]>ans) ans=cnt1[a];
    if(++cnt2>ans) ans=cnt2;
    }
    return N-ans;
    }
    int main()
    {
    cin >> N;
    for(int i=1,nbr1,nbr2;i<=N;i++)
    {
    cin >> nbr1 >> nbr2;
    if(!G.AddE(i,nbr1)||!G.AddE(i,nbr2))
    {
    cout << -1 << endl;
    return 0;
    }
    }
    G.dfs(1);
    cout << solve() << endl;
    system("pause");
    return 0;
    }

    0

    回复 -117-Join发表于2009-09-18 21:29
    哪位大牛帮忙看看我错哪里了
    它只得90分
    program fire;
    type
    arr=record
    l,r:longint;
    end;
    var
    num:array[1..50000]of longint;
    a:array[1..50000]of arr;
    b:array[1..50000]of longint;
    i,k,j,n:longint;
    begin
    readln(n);
    for i:=1 to n do
    readln(a[i].l,a[i].r);
    b[1]:=1;
    b[n]:=a[1].l;
    if a[b[n]].l=b[1]then b[n-1]:=a[b[n]].r
    else b[n-1]:=a[b[n]].l;
    i:=n-1;
    b[2]:=a[1].r;
    j:=2;
    while j<=i do
    begin
    if b<>a[b[i]].l then b:=a[b[i]].l
    else b:=a[b[i]].r;
    dec(i);
    if b[j-1]<>a[b[j]].r then b[j+1]:=a[b[j]].r
    else b[j+1]:=a[b[j]].l;
    inc(j);
    end;
    for i:=2 to n-1 do
    if(b<>a[b[i]].r)and(b<>a[b[i]].l)or(b<>a[b[i]].r)and(b<>a[b[i]].l)then
    begin
    write(-1);
    halt
    end;
    if(b[n]<>a[b[1]].l)and(b[n]<>a[b[1]].r)or(b[2]<>a[b[1]].l)and(b[2]<>a[b[1]].r)or(b[1]<>a[b[n]].l)and(b[1]<>a[b[n]].r)or(b[n-1]<>a[b[n]].l)and(b[n-1]<>a[b[n]].r)then
    begin
    write(-1);
    halt
    end;
    num[0]:=0;
    for i:=1 to n do
    begin
    a[b[i]].l:=i;
    num[i]:=0;
    end;
    for i:=1 to n do
    if a[i].l-i>=0 then inc(num[a[i].l-i])
    else inc(num[a[i].l-i+n]);
    j:=0;
    for i:=0 to n do
    if num[i]>j then j:=num[i];
    write(n-j);
    end.
    写的有点长

    0

    回复 fs302发表于2009-09-17 20:13
    分析:学一个好思想:正难则反!由顺序到乱序我们很难快速找到,但是我们知道如何从乱序变为顺序!解决本题利用了组合数学中置换群的思想。

    从第一个人处断开,将圆环的问题转化为序列的问题。如果可以,求出目标序列。求出目标序列复杂度O(n).
    求出目标序列右移0至n-1位置时,不需要移动的人数。将目标序列反转,再求出目标序列右移0至n-1位置时,不需要移动的人数。求不需要移动的人数最大等价于求需要移动的人数最小。复杂度O(n)。
    更详细的说:
    引进“相对有序”这个概念,当两个人满足C[j]-C[i]==j-i时,两个相对有序。
    题目要求最小的总代价,但是我们可以考虑倒过来想,要求最小的总代价亦即求最多有多少人不用移动,亦即相对有序。
    然后我们引进一个辅助变量T=C-I,{C-I>=0},T=C[i]-I+N,{C[i]-I<0},那么这个T[i]有什么意义呢?我们知道初始状态的编号是1-N,而目标状态是C[1]-C[N],那么C-I便是从目标状态到初始状态顺时针所要移动的距离,那么如果那么T值相等的两个同学则是相对有序的,亦即不用移动,我们只要找出最大的T然后N-Max(T)就是得到的结果,但是这样还不够,因为刚刚那样只是顺时针所要移动的距离,我们还要计算逆时针的到的结果,从顺时针和逆时针中找到最大的T,然后N-Max(T)才能够是正确结果.

    0

    回复 maxint64发表于2009-09-01 21:33
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    先是物理大发了——以为 b1,b2...bm是连续的
    看了牛们的题解 一次ac :)

    0

    回复 柔情使者发表于2009-08-20 15:44
    第一遍做的时候没有看题解,自己测了好几遍总是60分,看了n多大牛的解释才恍然大悟,竟然要正反两遍!!!唉,幸亏咱有测试数据,否则我可就惨了...
    O(n)的求目标队列算法,都说是冒泡排序,我没看出来,倒是有点像。

    0

    回复 maxiem发表于2009-08-18 20:55
    物理自重啊,嘿嘿。
    注意要正反两遍哦~
    9MS?
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 9ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:9ms

    (好像那个冒泡是口胡,大家不要被那个蒙了

    program fire;
    var
    st:array [1..50000,1..2] of longint;
    k,final:array [0..50000] of longint;
    ex:array [1..50000] of boolean;
    p,max,i,n:longint;
    begin
    fillchar (st,sizeof(st),0);
    fillchar (ex,sizeof(ex),0);
    fillchar (final,sizeof(final),0);
    fillchar (k,sizeof(k),0);
    readln (n);
    for i:=1 to n do readln (st,st);
    final[1]:=1;p:=2;ex[1]:=true;
    for i:=1 to n do begin
    if ex[st[final[i],1]]=false then begin
    final[p]:=st[final[i],1];
    ex[st[final[i],1]]:=true;
    inc(p);
    end
    else if ex[st[final[i],2]]=false then begin
    final[p]:=st[final[i],2];
    ex[st[final[i],2]]:=true;
    inc(p);
    end;
    end;
    if p-1<>n then begin
    writeln (-1);
    halt;
    end;
    max:=0;
    for i:=1 to n do if final[i]>=i then inc(k[final[i]-i]) else inc(k[n-i+final[i]]);
    for i:=0 to n-1 do if k[i]>max then max:=k[i];
    fillchar (k,sizeof(k),0);
    for i:=n downto 1 do if final[i]>=n-i+1 then inc(k[final[i]-n+i-1]) else inc(k[final[i]+i-1]);
    for i:=0 to n -1 do if k[i]>max then max:=k[i];
    writeln (n-max);
    end.

    0

    回复 suning发表于2009-08-14 09:43
    啊呜~
    一年前误解了题意~
    一年后理解了题意~
    然后就是1次美妙的AC

    PS:[误]解[理]解~~~[物理]?

    0

    回复 fengwuliu发表于2009-08-13 17:20
    lgxcgd说的太对了!太感谢了5555

    0

    回复 Matt发表于2009-08-11 22:28
    NOIP也会考高等数学...

    由于原图是环,所以置换群可表示为一次循环。作差是个好方法。

    但求冒泡排序是怎么作的

    0

    回复 3830372发表于2009-08-11 21:28
    Flag   Accepted
    题号   P1008
    类型(?)   模拟
    通过   1504人
    提交   4282次
    通过率   35%
    难度   3

    提交 讨论 题解 状态

    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 尖端才子发表于2009-08-11 11:14
    纪念一下……第1500个AC……

    Flag    Accepted
    题号   P1008
    类型(?)   模拟
    通过   1500人
    提交   4274次
    通过率   35%
    难度   3

    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 SecretAgent发表于2009-08-10 14:02
    置换群是正解

    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 yangbei发表于2009-08-07 14:57
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 338ms
    ├ 测试数据 05:答案正确... 322ms
    ├ 测试数据 06:答案正确... 306ms
    ├ 测试数据 07:答案正确... 338ms
    ├ 测试数据 08:答案正确... 338ms
    ├ 测试数据 09:答案正确... 322ms

    ├ 测试数据 10:答案正确... 306ms

    Accepted 有效得分:100 有效耗时:2270ms

    算镜像时偷了点懒,不过也算一遍AC了

    0

    回复 ja_son发表于2009-08-06 15:44
    a:拆环成队,寻求目标队列。
    b:b1,b2...bm不是连续的,而且是任意的。只要有成立目标队列,与原来的队列相匹配就可以知道有多少(设为n个)需要移动位置,则代价就是n。
    c:目标队列有多种情况,可以反转,也可以左右移动。

    0

    回复 1s发表于2009-08-03 17:56

    如对本题有疑问可以参看我的题解:
    http://xujieqi.blog.hexun.com/35722312_d.html

    0

    回复 DMKaplony发表于2009-07-30 15:15
    当时的时间限制好像是2s。。有个题解说把1定为第一项然后进行冒泡排序。。不过这里是1s 啊。。。也行只有置换群了吧。

    0

    回复 xusc_2009发表于2009-07-28 14:30
    看不懂,只好搁浅
    什么时候想清楚了再做

    0

    回复 董发表于2009-07-24 19:11
    program p1008;
    var i,n,k,j,sum1,sum2,ans,max:longint;
       a,b,w,d,c:array[0..50005] of longint;

    begin
    readln(n);
    for i:=1 to n do
    readln(a[i],b[i]);
    w[1]:=1; w[2]:=a[w[1]];
    k:=1;

    repeat
    inc(k);
    if w[k-1]=a[w[k]] then w[k+1]:=b[w[k]]
      else if w[k-1]=b[w[k]] then w[k+1]:=a[w[k]]
       else begin
           writeln(-1);
           exit;
           end;
    until k=n;
    if w[n+1]<>w[1] then
           begin
           writeln(-1);
           exit;
           end;

    for i:=1 to n do
    begin
    a[i]:=w[i]-i;
    b[i]:=w[n-i+1]-i;
    if a[i]<0 then a[i]:=a[i]+n;
    if b[i]<0 then b[i]:=b[i]+n;
    inc(c[a[i]]);
    inc(d[b[i]]);
    end;
    for i:=0 to n-1 do
    begin
    if ans<c[i] then ans:=c[i];
    if ans<d[i] then ans:=d[i];
    end;
    writeln(n-ans);  
    end.

    0

    回复 我飞发表于2009-07-23 21:00
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 93狒狒发表于2009-07-23 20:59
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    秒杀......

    0

    回复 fjxmlhx发表于2009-07-22 13:15
    置换群,做2n次,顺时针和逆时针.
    对于一个置换,最小操作费用是所有循环长度的和.因此实际上是找出2n个置换中哪个置换循环长度为1的数量最多.

    0

    回复 340508965发表于2009-07-21 15:01
    ⊙﹏⊙b汗
    不知道的以为这是数学竞赛......
    ...
    我的数论与图论可以说脑袋里空白一片.........
    怎么办,我的竞赛啊
    ........

    算了 看了题解 大家写的
    总算弄懂这道题了
    先前以为b1,b2,b3..bm是连续的
    没想到是任意的!!!!!!!!!

    诶 叹悲歌未切 为撼奈何编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    总算AC了


    program p1008;
    var i,n,k,j,sum1,sum2,ans,max:longint;
    a,b,w,d,c:array[0..50005] of longint;

    begin
    readln(n);
    for i:=1 to n do
    readln(a[i],b[i]);
    w[1]:=1; w[2]:=a[w[1]];
    k:=1;

    repeat
    inc(k);
    if w[k-1]=a[w[k]] then w[k+1]:=b[w[k]]
    else if w[k-1]=b[w[k]] then w[k+1]:=a[w[k]]
    else begin
    writeln(-1);
    exit;
    end;
    until k=n;
    if w[n+1]<>w[1] then
    begin
    writeln(-1);
    exit;
    end;

    for i:=1 to n do
    begin
    a[i]:=w[i]-i;
    b[i]:=w[n-i+1]-i;
    if a[i]<0 then a[i]:=a[i]+n;
    if b[i]<0 then b[i]:=b[i]+n;
    inc(c[a[i]]);
    inc(d[b[i]]);
    end;
    for i:=0 to n-1 do
    begin
    if ans<c[i] then ans:=c[i];
    if ans<d[i] then ans:=d[i];
    end;
    writeln(n-ans);
    end.

    0

    回复 zsy90943发表于2009-07-18 00:51
    构造巧妙、、看来还是要学好数论和图论额、、、、

    0

    回复 POM无敌牛B发表于2009-07-16 11:47
    编译通过...
    ├ 测试数据 01:运行超时...
    ├ 测试数据 02:运行超时...
    ├ 测试数据 03:运行超时...
    ├ 测试数据 04:运行超时...
    ├ 测试数据 05:运行超时...
    ├ 测试数据 06:运行超时...
    ├ 测试数据 07:运行超时...
    ├ 测试数据 08:运行超时...
    ├ 测试数据 09:运行超时...

    ├ 测试数据 10:运行超时...

    Unaccepted 有效得分:0 有效耗时:0ms
    无奈 哪位哥哥救救我

    0

    回复 yxy发表于2009-06-16 18:16
    把置换解释成度为2图,真有才.
    求出序列,正反分别做一次差就行了.

    0

    回复 sxpeter发表于2009-06-14 16:56
    讲建环吧。数组w表示环,我用的是一种类似并查集的方法。
    begin
    read(n);
    for i:=1 to n do read(a[i],b[i]);
    t:=2;w[1]:=1;w[2]:=a[1];
    while true do begin
    if a[w[t]]<>w[t-1]then w[t+1]:=a[w[t]]//是否在左边
    else if b[w[t]]<>w[t-1]then w[t+1]:=b[w[t]]//是否在右边
    else begin writeln(-1);halt;end;//失败判断
    inc(t);
    if t>n then break;
    end;
    if w[n+1]<>w[1]then begin writeln(-1);halt;end;//本句一定要加!!!!!!
    end.

    0

    回复 lgxcgd发表于2009-05-17 20:24
    首先把这个圈看做一个图,每个同学看做一个顶点。因为要形成环,所以每个顶点的度必须为2。

    如果存在度数不为2的顶点,那么整个图无法构成一个环,即“无论怎么调整都不能符合每个同学的愿望”输出-1。

    如果是一个环,那么就遍历图,生成以第1个顶点为开头的序列。现在就要求出最小移动的代价。

    在理解题意所述的调整方式中,要注意实际上就是把M个在错误位置上的人移动到正确的位置上,代价为M。一次下令移动即可。

    假如生成的目标序列为1,5,3,2,4。我们现在就需要比较它和初始状态1,2,3,4,5,看有几个人离开了原来的位置。但这个序列实际代表的是一个环,而且方向正反有两种,就需要把初始序列正反分别转N次,和得到的序列比较,看其中最少有几个位置上的人编号不相同,就得到了我们要求的最小代价。

    上述方法有大量冗余。但可以发现转来转去不管怎么转,任意两个人之间的相对位置关系在这过程中都不会变。于是想到做差,如果差小于0则加上N。

    1 5 3 2 4

    - 1 2 3 4 5

    0 3 0 3 4
    这表示序列1,5,3,2,4不转动时1,3两个人在原来的位置上,转动3个位置后5和2两个人在原来的位置上,转动4个位置后只有4一个人会在原来的位置上。这就是说,1,5,3,2,4与1,2,3,4,5在旋转后最多有2个位置上的人编号相同,即最少有3个位置上的人编号不相同。同理要反转再求一次。

    记录每个不同的差值的个数,取其最大值P,即不调换次数最大的。结果N-P就是调换次数最小的。

    0

    回复 src250发表于2009-05-14 08:27

    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    切记:重新构图时一定要对数组清空!我的第一次只有50分,就是这个原因!

    0

    回复 love19960108发表于2009-04-26 17:59
    这题可以用C++这样做么??
    #include <iostream>
    #include <cassert>
    using namespace std;
    long N,seq[50001],p=1;
    class{
    private:
    long nbr[50001][3];
    bool flag[50001];
    bool isnbr(long v1,long v2){
    for(int i=1;i<=nbr[v1][0];i++)
    if(nbr[v1][i]==v2) return true;
    return false;
    }
    public:
    bool AddE(long v1,long v2){
    if(isnbr(v1,v2)) return true;
    else if(nbr[v1][0]==2||nbr[v2][0]==2) return false;
    else{
    nbr[v1][++nbr[v1][0]]=v2;
    nbr[v2][++nbr[v2][0]]=v1;
    return true;
    }
    }
    void dfs(long i){
    assert(!flag[i]);
    flag[i]=true,seq[p++]=i;
    for(int j=1;j<=nbr[i][0];j++){
    if(!flag[nbr[i][j]]){
    dfs(nbr[i][j]);
    break;
    }
    }
    }
    }G;
    long solve(){
    long cnt1[50001]={0},cnt2[50001]={0},ans=0;
    for(int i=1,a,b;i<=N;i++){
    a=seq[i]-i;
    if(a<0) a+=N;
    b=seq[i]-(N+1-i);
    if(b<0) b+=N;
    if(++cnt1[a]>ans) ans=cnt1[a];
    if(++cnt2>ans) ans=cnt2;
    }
    return N-ans;
    }
    int main(){
    cin >> N;
    for(int i=1,nbr1,nbr2;i<=N;i++){
    cin >> nbr1 >> nbr2;
    if(!G.AddE(i,nbr1)||!G.AddE(i,nbr2)){
    cout << -1 << endl;
    return 0;
    }
    }
    G.dfs(1);
    cout << solve() << endl;
    return 0;
    }

    0

    回复 voyagec2发表于2009-03-18 15:53
    难理解,不过算法很精妙

    0

    回复 pRoevollove发表于2009-02-25 23:49
    天,把(p[i]-i+n)mod n理所当然地打成了abs(p[i]-i)
    结果一直50分……还一直以为自己构造错了……

    ps 我可以过楼下的范例哦

    0

    回复 ufo172849z发表于2009-01-24 23:05
    ms楼下的程序不能处理这种反例(测试数据还是不够强啊)
    6
    2 3
    1 3
    1 2
    5 6
    4 6
    4 5
    应该输出-1的吧?因为是两个环

    var a,b:array[0..50000]of longint;
    c:array[0..50000,1..2]of longint;
    d:array[0..50000]of boolean;
    i,j,k,m,n,max:longint;
    can:boolean;

    begin
    readln(n);
    for i:=1 to n do
    readln(c,c);
    b[0]:=c[1,1]; b[n]:=c[1,1];
    fillchar(d,sizeof(d),0);
    k:=1;
    can:=true;
    for i:=1 to n-1 do
    begin
    if d[k] then can:=false;
    b[i]:=k; d[k]:=true;
    if b=c[k,1] then k:=c[k,2]
    else if b=c[k,2] then k:=c[k,1]
    else can:=false;
    if not can then break;
    end;
    if can then
    if b[n]<>k then can:=false;
    if can then
    begin
    max:=-1;
    fillchar(a,sizeof(a),0);
    for i:=1 to n do
    inc(a[(b[i]-i+n) mod n]);
    for i:=0 to n-1 do
    if a[i]>max then max:=a[i];
    fillchar(a,sizeof(a),0);
    for i:=1 to n do
    inc(a[(b[n-i+1]-i+n)mod n]);
    for i:=1 to n-1 do
    if a[i]>max then max:=a[i];
    writeln(n-max);
    end
    else
    writeln(-1);
    end.

    0

    回复 tangdongjian发表于2009-01-23 22:17
    我在做镜像时把原先max直接覆盖上了,注意

    0

    回复 永恒888发表于2009-10-26 22:50
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 tangkunjie发表于2009-06-04 19:50
    挺烦人的题目

    0

    回复 ykspeter发表于2008-11-13 20:32
    program fire(input,output);
    var
    n,i,j,k,max,v:longint;
    a:array[0..100000,1..2] of longint;
    b,c:array[0..100000] of longint;
    begin
    readln(n);
    for i:=1 to n do readln(a,a);
    for i:=1 to n do
       begin
        k:=0;
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if (k=4) or (k=3)
        then begin
           writeln('-1');
           exit
           end
       end;
    b[1]:=1;i:=2;k:=a[1,1];j:=1;
    repeat
      b[i]:=k;
      inc(i);
      v:=k;
      if a[k,1]<>j
      then k:=a[k,1]
      else k:=a[k,2];
      j:=v;
    until i=n+1;
    fillchar(c,sizeof(c),0);
    for i:=1 to n do inc(c[(b[i]-i+n)mod n]);
    for i:=0 to n-1 do
       if c[i]>max
       then max:=c[i];
    fillchar(c,sizeof(c),0);max:=0;
    for i:=1 to n do inc(c[(b[n-i+1]-i+n)mod n]);
    for i:=n-1 downto 0 do
       if c[i]>max
       then max:=c[i];
    writeln(n-max);
    end.

    0

    回复 getuojian发表于2008-11-10 13:38
    #include<stdio.h>
    #include<memory.h>

    const int maxn=50010;
    int n;
    int f[maxn][2];
    int goal[maxn];
    int ans=maxn;
    int hash[maxn];

    bool SET_ORI(){
    bool flag[maxn];
    memset(flag, true, sizeof(flag));
    goal[1]=1; flag[1]=false;
    for (int i=1; i<=n-1; i++){
    if (flag[f[goal[i]][0]]){
    goal=f[goal[i]][0];
    flag[f[goal[i]][0]]=false;
    continue;
    }
    if (flag[f[goal[i]][1]]){
    goal=f[goal[i]][1];
    flag[f[goal[i]][1]]=false;
    continue;
    }
    return false;
    }
    if ((goal[n]!=f[1][0]) && (goal[n]!=f[1][1]))
    return false;
    return true;
    }
    int SWAP(int i, int j){
    int t=goal[i];
    goal[i]=goal[j];
    goal[j]=t;
    return 0;
    }

    int min(int i, int j){
    return i>j?j:i;
    }
    int HASH(){
    for(int i=1; i<=n; i++)
    hash[i]=goal[i]-i+n;
    return 0;
    }

    int CALC(){
    int temp[maxn*2], back=0;
    memset(temp, 0, sizeof(temp));
    for (int i=1; i<=n; i++)
    temp[hash[i]%n]++;
    for (int i=1; i<=2*n-1; i++)
    if (temp[i] > back)
    back=temp[i];
    return back;
    }

    int main(){
    freopen("fire.in", "r", stdin);
    freopen("fire.out", "w", stdout);
    scanf("%d", &n);
    for (int i=1; i<=n; i++)
    scanf("%d %d", &f[i][0], &f[i][1]);
    if (!SET_ORI()){
    printf("-1");
    return 0;
    }
    //forward
    HASH();
    ans=min(ans, n-CALC());
    //backward
    for (int i=1; i<=n/2; i++)
    SWAP(i,n-i+1);
    HASH();
    ans=min(ans, n-CALC());

    printf("%d", ans);
    return 0;
    }

    0

    回复 IVORY发表于2008-11-06 10:46
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    CHEAT的...

    0

    回复 storey p发表于2008-11-05 14:19
    回447389831:
    exit换成halt

    0

    回复 FenXy发表于2008-11-04 08:28
    艺术p245

    0

    回复 hlq发表于2008-11-01 14:31
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms

    求不在位置上的人数
    a【i】 第i位上的同学编号
    for i:=1 to n do
    begin
    inc(b[(a[i]-i+n) mod n])
    end;
    max:=0;
    for i:=0 to n-1 do
    if b[i]>max then max:=b[i];
    fillchar(b,sizeof(b),0);
    for i:=1 to n do
    begin
    inc(b[(a[i]-(n-i+1)+n)mod n]);//对称
    end;
    for i:=0 to n-1 do
    if b[i]>max then max:=b[i];

    0

    回复 Will~骷髅发表于2008-10-30 21:37
    编译通过...
    ├ 测试数据 01:运行超时...
    ├ 测试数据 02:运行超时...
    ├ 测试数据 03:运行时错误...|错误号: -1073741819
    ├ 测试数据 04:运行时错误...|错误号: -1073741819
    ├ 测试数据 05:运行时错误...|错误号: -1073741819
    ├ 测试数据 06:运行时错误...|错误号: -1073741819
    ├ 测试数据 07:运行时错误...|错误号: -1073741819
    ├ 测试数据 08:运行时错误...|错误号: -1073741819
    ├ 测试数据 09:运行时错误...|错误号: -1073741819

    ├ 测试数据 10:运行时错误...|错误号: -1073741819

    Unaccepted 有效得分:0 有效耗时:0ms

    怎么会这样???

    0

    回复 悲伤逆流成河发表于2008-10-28 22:13
    #include <iostream>
    #include <fstream>
    using namespace std ;

    int hash[50001];
    int n , i , j , t , maxs(0) ;

    inline void HASH ( int e[] )
    {
    for ( i = 1 ; i <= n ; i++ )
    {
    e[i] -= i ;
    if ( e[i] < 0 ) e[i] += n ;
    hash[e[i]]++ ;
    }
    for ( i = 0 ; i < 50001 ; i++ )
    if ( maxs < hash[i] ) maxs = hash[i] ;
    }

    int main(){
    ifstream fin ("fire.in") ;
    ofstream fout ("fire.out") ;

    fin >> n ;
    int e[n+1] , h[n+1][2] , e2[n+1];
    bool f[n+1] ;
    for ( i = 1 ; i <= n ; i++ )
    {
    f[i] = false ;
    fin >> h[i][0] >> h[i][1] ;
    }
    e[1] = 1 ;
    f[1] = true ;
    for ( i = 2 ; i <= n ; i++ )
    {
    if ( e < 0 ) { fout << -1 << endl ; exit(0) ; }
    if ( !f [ h[ e ][0] ] ) e[i] = h[ e ][0] ;
    if ( !f [ h[ e ][1] ] ) e[i] = h[ e ][1] ;
    f[ e[i] ] = true ;
    }
    for ( i = 1 , j = n ; i <= n ; i++,j-- ) e2[j] = e[i] ;
    HASH ( e ) ;
    memset ( hash , 0 , sizeof ( hash ) ) ;
    HASH ( e2 ) ;
    fout << n - maxs << endl ;
    }

    0

    回复 evelynhe发表于2008-10-26 16:31
    “置换群思想...今天刚明白...

    先构造新数列(要构造两次,否则只有70分),然后向右计算相对位置差,然后累加记录数组,然后用N减去相对位置差累加值最大的,就是答案... ”

    这是真的

    0

    回复 true1023发表于2008-10-25 09:32
    置换群的基本概念
    利用原序列和目标序列每个元素的绝对位置差来求出原序列每个元素对于目标序列的相对位置,找相对位置相同的最多的元素数,用总元素数减去它即为结果。

    0

    回复 447389831发表于2008-10-21 09:45
    program fire(input,output);
    var
    n,i,j,k,max,v:longint;
    a:array[0..100000,1..2] of longint;
    b,c:array[0..100000] of longint;
    begin
    readln(n);
    for i:=1 to n do readln(a,a);
    for i:=1 to n do
       begin
        k:=0;
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if (k=4) or (k=3)
        then begin
           writeln('-1');
           exit
           end
       end;
    b[1]:=1;i:=2;k:=a[1,1];j:=1;
    repeat
      b[i]:=k;
      inc(i);
      v:=k;
      if a[k,1]<>j
      then k:=a[k,1]
      else k:=a[k,2];
      j:=v;
    until i=n+1;
    fillchar(c,sizeof(c),0);
    for i:=1 to n do inc(c[(b[i]-i+n)mod n]);
    for i:=0 to n-1 do
       if c[i]>max
       then max:=c[i];
    fillchar(c,sizeof(c),0);max:=0;
    for i:=1 to n do inc(c[(b[n-i+1]-i+n)mod n]);
    for i:=n-1 downto 0 do
       if c[i]>max
       then max:=c[i];
    writeln(n-max);
    end.
    90 分,牛人门帮看下把

    0

    回复 cnfnje1发表于2008-10-17 18:12
    置换群.....是什么?
    readln(n);
    for i:=1 to n do readln(a[i],b[i]);
    c[1]:=1; c[2]:=a[1];
    for i:=3 to n do if c=a[c] then c[i]:=b[c]
    else if c=b[c] then c[i]:=a[c]
    else begin writeln(-1); halt end;
    if c[n]<>b[1] then begin writeln(-1); halt end;
    fillchar(d,sizeof(d),0);
    for i:=1 to n do inc(d[(c[i]-i+n)mod n]);
    for i:=0 to n-1 do if d[i]>m then m:=d[i];
    fillchar(d,sizeof(d),0);
    for i:=1 to n do inc(d[(c[i]+i-1)mod n]);
    for i:=0 to n-1 do if d[i]>m then m:=d[i];
    writeln(n-m);
    是么?

    0

    回复 lyrics发表于2008-10-12 19:55
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    技巧性比较强吧,楼下不必构造2次,计算时从头至尾算一次,再倒过来算一次就行了

    0

    回复 LV.唱响发表于2008-10-05 08:38
    置换群思想...今天刚明白...

    先构造新数列(要构造两次,否则只有70分),然后向右计算相对位置差,然后累加记录数组,然后用N减去相对位置差累加值最大的,就是答案...

    0

    回复 宇智波带波斯猫发表于2008-10-05 08:33
    Flag   Accepted
    题号   P1008
    类型(?)   其它
    通过   1065人
    提交   3000次
    通过率   35%
    难度   3

    第3000个提交的

    0

    回复 鸳鸯羡发表于2008-09-28 18:19
    #include <iostream>
    using namespace std ;

    int hash[50001];
    int n , i , j , t , maxs(0) ;

    inline void HASH ( int e[] )
    {
    for ( i = 1 ; i <= n ; i++ )
    {
    e[i] -= i ;
    if ( e[i] < 0 ) e[i] += n ;
    hash[e[i]]++ ;
    }
    for ( i = 0 ; i < 50001 ; i++ )
    if ( maxs < hash[i] ) maxs = hash[i] ;
    }

    int main(){
    cin >> n ;
    int e[n+1] , h[n+1][2] , e2[n+1];
    bool f[n+1] ;
    for ( i = 1 ; i <= n ; i++ )
    {
    f[i] = false ;
    cin >> h[i][0] >> h[i][1] ;
    }
    e[1] = 1 ;
    f[1] = true ;
    for ( i = 2 ; i <= n ; i++ )
    {
    if ( e < 0 ) { cout << -1 << endl ; exit(0) ; }
    if ( !f [ h[ e ][0] ] ) e[i] = h[ e ][0] ;
    if ( !f [ h[ e ][1] ] ) e[i] = h[ e ][1] ;
    f[ e[i] ] = true ;
    }
    for ( i = 1 , j = n ; i <= n ; i++,j-- ) e2[j] = e[i] ;
    HASH ( e ) ;
    memset ( hash , 0 , sizeof ( hash ) ) ;
    HASH ( e2 ) ;
    cout << n - maxs << endl ;
    }

    80分

    0

    回复 月光疾风发表于2008-09-25 13:03
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    纪念我第200次提交!过第79题。。。。

    0

    回复 ghostplant发表于2008-09-20 19:48
    #include <iostream>
    #include <fstream>
    #include <cassert>
    using namespace std;
    long N,seq[50001],p=1;
    class{
    private:
    long nbr[50001][3];
    bool flag[50001];
    bool isnbr(long v1,long v2){
    for(int i=1;i<=nbr[v1][0];i++)
    if(nbr[v1][i]==v2) return true;
    return false;
    }
    public:
    bool AddE(long v1,long v2){
    if(isnbr(v1,v2)) return true;
    else if(nbr[v1][0]==2||nbr[v2][0]==2) return false;
    else{
    nbr[v1][++nbr[v1][0]]=v2;
    nbr[v2][++nbr[v2][0]]=v1;
    return true;
    }
    }
    void dfs(long i){
    assert(!flag[i]);
    flag[i]=true,seq[p++]=i;
    for(int j=1;j<=nbr[i][0];j++){
    if(!flag[nbr[i][j]]){
    dfs(nbr[i][j]);
    break;
    }
    }
    }
    }G;
    long solve(void){
    long cnt1[50001]={0},cnt2[50001]={0},ans=0;
    for(int i=1,a,b;i<=N;i++){
    a=seq[i]-i;
    if(a<0) a+=N;
    b=seq[i]-(N+1-i);
    if(b<0) b+=N;
    if(++cnt1[a]>ans) ans=cnt1[a];
    if(++cnt2>ans) ans=cnt2;
    }
    return N-ans;
    }
    int main(){
    cin >> N;
    for(int i=1,nbr1,nbr2;i<=N;i++){
    cin >> nbr1 >> nbr2;
    if(!G.AddE(i,nbr1)||!G.AddE(i,nbr2)){
    cout << -1 << endl;
    return 0;
    }
    }
    G.dfs(1);
    cout << solve() << endl;
    return 0;
    }

    0

    回复 zzh19950802发表于2008-09-17 19:29
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案错误... ├ 标准行输出
     ├ 错误行输出
    ├ 测试数据 05:答案错误... ├ 标准行输出
     ├ 错误行输出
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 462ms
    ├ 测试数据 08:答案正确... 369ms
    ├ 测试数据 09:答案正确... 384ms
    ├ 测试数据 10:答案错误...程序输出比正确答案长
    为什么我的程序不对?
    #include <iostream>
    using namespace std;
    #define MAXN 50000
    int man[MAXN+2][2];
    int cercle[MAXN+2]={0,1};
    int used[MAXN+2]={0};
    int reduce[2][MAXN+2]={0};
    int n;
    int main()
    {
    long i,p,q=1,t;
    int max=0;
    cin>>n;
    for (i=1;i<=n;i++) cin>>man[i][0]>>man[i][1];
    p=man[q][1];
    for (i=2;i<=n+1;i++)
    {
    if (man[q][1]==p)
    {
    p=q;
    q=man[q][0];
    }
    else
    {
    if(man[q][0]!=p) break;
    p=q;
    q=man[q][1];
    }
    if(used[q]) break;
    else used[q]=1;
    cercle[i]=q;
    }
    if (i<=n+1) cout<<-1;
    else
    {
    for (i=1;i<=n;i++)
    {
    if((t=cercle[i]-i)<0) t+=n;
    reduce[0][t]++;
    if (reduce[0][t]>max) max=reduce[0][t];
    if ((t=cercle[i]-n+i-1)<0) t+=n;
    if (reduce[1][t]>max) max=reduce[1][t];
    }
    cout<<n-max;
    }
    return 0;
    }

    0

    回复 liaorc发表于2008-09-16 17:56
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 cxy450090074发表于2008-09-04 13:34
    oh no

    0

    回复 Lost.G发表于2008-08-22 15:49
    我在想``怎么样才能不看错这题呢

    0

    回复 bonism发表于2008-08-14 21:30
    时间复杂度O(N)。。。

    原来我一直把题意理解错。。。囧!!。。

    关于“置换群”,请看LRJ的《算法艺术与信息学竞赛》P245那一小节,还是比较好理解的。

    0

    回复 lemon_cn发表于2008-08-08 15:55
    热烈庆祝用pascal AC的第二题~
    p.s.我是C++的~~

    0

    回复 oipn4e2发表于2008-08-05 21:36
    解决效率不高,但AC了。

    0

    回复 notblack发表于2008-08-01 09:17
    用距离来分类,统计在原位的最大人数,奇怪的是
    b[1]:=1;
    b[2]:=a[1,1];
    b[n]:=a[1,2];

    建环的时候,上面的改成
    b[1]:=1;
    b[2]:=a[1,2];
    b[n]:=a[1,1];

    最后一个点却过不了,太奇怪了.

    0

    回复 332404521发表于2008-07-14 13:53
    对于初三刚刚中考完的我,要理解这题的意思是万万不能的。。。
    看题解我知道了应该怎么做,但那不是我的,所以不做了。。。
    哪天能证明出来那啥再来做

    0

    回复 Sheeta发表于2007-11-14 15:45
    好简单啊
    直接贪啊
    (P.S.置换群?什么东东...)

    0

    回复 mingyueyucai发表于2007-11-09 21:22
    我代码写了老长老长,结果还是只过了8个点,有没有搞错?
    我想请问一下,我和大家的一样,先排列出目标状态.然后确定初始状态时使得最多的人在目标位置上,然后交换.但是得到的答案总是偏大一点.
    然后我又把所有可以使最多的人在原位目标位置上的可能都尝试了一编(包括正反两个目标状态),结果还是只能过8个点,有2个点死都过不了!
    我的算法有什么问题吗?

    0

    回复 luanjiyang发表于2007-11-08 08:44
    很委琐的说 我提交了8遍。。
    0→0→10→10→10→10→70→AC

    • -||

    0

    回复 lonelycorn发表于2007-11-05 23:31
    数论……好底歇的东西。

    0

    回复 gamejifan发表于2007-11-04 11:15
    这题的叙述,让我误会了一年多。tzkq……3q..要早知道是这种意思早就ac了这题。。显然没什么大意思,看过组合数学或者学过群论的都懂。。ms跟polya计数法那个循环的意思。。

    写的时候竟然因为交换的时候写错一个字母wa。我汗。

    0

    回复 Alexandria发表于2007-11-01 13:33
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    好强大的题啊,不看题解还真不会!

    0

    回复 clfhaha1234发表于2007-10-30 18:09
    请问什么是置换群啊?可以讲讲吗?………………

    0

    回复 rleepas发表于2007-10-30 13:18
    楼下都是正解?
    ......

    0

    回复 Ice_Msk发表于2007-10-18 20:35
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    什么是置换群?不知道。。。照样过。。。。

    0

    回复 junlonely发表于2007-10-18 20:13
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 江南不才发表于2007-10-11 16:19
    排序法这里会超时~~~~~
    比赛的时间是2S~~
    这里是1S~~
    (_)

    0

    回复 秒杀群众发表于2007-10-10 17:05
    居然是置换群。。。
    对了。。。什么是置换群...
    上网查啊!!!

    0

    回复 southstarj1发表于2007-10-02 18:50
    思想:
    置换群。(相关知识自己查)
    对于一组数据,按各人的意愿排出一个序列,
    如果无法排出,就输出-1。
    再将环状序列变成链状,则这个目标序列为一个置换群,
    与原序列(按1到n的一列)满足:
    交换的最少人数等于目标序列与原序列不重合的人数。
    因为总共有2n个目标序列(正反各n种),都算一遍就行了。

    步骤:
    1. 读入数据;
    2. 构造一个目标序列;
    3. 统计该序列中元素位置与该元素在原序列位置的差值(同一方向)为i{i ∈ [0, n)}的元素个数;
    4. 将该序列的反序统计一遍;
    5. 从这些数据中选取一个最大的值max;
    6. 输出n - max;

    注意:
    构造目标序列时判断能否构造的条件;
    统计一次差值的复杂度是O(n);
    统计差值的目的是求与原序列最多的重合人数;

    0

    回复 wangjin5发表于2007-09-19 22:38
    好经典的题奥
    确实有难度

    0

    回复 the_melody发表于2007-09-03 17:58
    Accepted 有效得分:100 有效耗时:0ms
    好经典的题奥

    0

    回复 richardxx发表于2007-08-22 17:36
    下面程序是错的,不好意思,弄错地方了....

    0

    回复 sm-star发表于2007-08-21 15:18
    题目所求就是每次进行连续交换的人数总和,这样,一个看似复杂的题目就变的异常的简单了!

    0

    回复 wasyyyy发表于2007-08-11 02:05
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    HOHO~~~看讨论的时候看到有人提到‘置换群’这个东西,突然想起来我刚买的一本组合数学上有这么一块东西,就拿过来看了。。。。
    然后就出现上面的东西了。。。。置换群,本来想求轮换的,发现轮换比较多,还是找不参与交换的比较好记。。。。

    优化的方法。。。我看了下好象不只一个人讲过了。。。而且似乎我跟他们的都一样(没仔细看)所以就不说了。。。效率是O(n)的。。不用建环。

    0

    回复 angieqiu发表于2007-08-10 22:49
    怎么判断建环失败啊?我的程序虽然AC但总觉得方法很傻

    0

    回复 梦ぁ逍遥发表于2007-07-17 13:45
    想到了用t[i]=b[i]-i表示环
    却没想到镜像..

    十分感谢visister
    让我从90分中挣扎出来...

    0

    回复 visister发表于2007-06-01 00:12
    首先明显地可以知道我们需要对于目标状态建立出一个环。如果无法建立这个环,那么结果一定是-1,当建立好环以后可以知道最小移动代价一定等于最少的不在目标位置上的人数。那么我们可以对目标环进行顺时针旋转1~n-1之中任意一个,答案就一定等于旋转中的不在自己位置上的人数最少的那样的环的状态。但是对于50000的数据,我们如果要将环旋转1~n-1次,那么总共加上判断不在自己位置上的人数时间复杂度为O(n^2),显然在限定时间内是无法出解的。因此我们进行逆向思维:不在自己位置上最少的人数就一定会等于总人数减去在自己位置上最多的人数(仔细想想),那么我们就将该问题转化为了求在自己的位置上最多的人数,这样一来,我们对初始目标环中每一个位置进行判断需要旋转多少次可以回到自己位置上,每一个人的选择都将映射到[0..n-1]的数组中,选取当中最大的情况就为所求,但是考虑到环可以反转,那么我们还需要将环再求一次镜像,就可以得到初始目标需要旋转多少次可以得到在自己位置上最多的人数的环的状态,最后通过总的人数减去它即为问题所求,时间复杂度为O(n);

    0

    回复 pyh119发表于2006-11-16 20:11
    哪个人不小心失火了找我啊!!!

    PS:我是安徽省芜湖市119接线员....

    0

    回复 maomingming发表于2006-11-06 18:40
    考虑旋转后最多可能重合的情况,另要注意圈可以反过来

    0

    回复 qian5发表于2006-09-30 21:35
    直接输出‘-1’有一个点过

    0

    回复 BambooLeaf发表于2006-09-26 18:17
    见过的最牛最简单的方法……
    将此题转换为冒泡排序,记录下所有交换的次数和两数间的距离,加上就行了……—__—|||
    具体是这样的,我们反向思维,本来是要求一个有序数列求出成为无序数列的代价,现在我们把无序数列(即目标数列)进行冒泡排序,然后……就是这样……
    看完之后,偶巨汗……

    0

    回复 xcjzj发表于2006-09-26 17:18
    每组数据确定两组相对位置关系,并且这两组互为镜像。
    对于某一种排列方式,不在需要位置上的人数即为当前状态到目标状态的最小代价。
    先找出其中一种排列方式。由于目标状态可以通过旋转而使得部分人的变化次数减少,所以找出每个人通过某一固定方向旋转到达目标位置的旋转次数。找到某一次数,使得拥有这个次数的人数最多。那么,通过旋转这一最多人拥有的次数,即可使得尽可能多的人不通过交换直接到达目标位置。于是,不拥有这一旋转次数的人数即为这一状态下的最小代价。
    然后,用现在的目标状态找出其镜像状态,并且用上述方法再找一遍最小代价,与前面的结果比较,较小值即为答案。
    另外,题目中会出现一些无解的情况:
    1.某个人被“要”的次数多于两次,也就是说有多于两个的人想要与他(她)邻座,那么无解。
    2.根据要求得出的目标状态为多于一个的环,也无解。

    0

    回复 东邪歪刀发表于2006-07-28 17:27
    提交了若干次……残念……

    0

    回复 sugar发表于2006-07-28 16:26
    这题比赛时真有人ac?
    真不好想
    为什么得开longint啊?

    0

    回复 晶星发表于2006-07-25 13:29
    排列本质不同的只有二种 正着和反着的
    检验几个人不在位置上用数学方法:)模拟法超时的

    0

    回复 tzkq发表于2006-07-23 04:37
    注意别误解题意 b1,b2....bm并不指连续位置上的数

    0

    回复 Coldwings发表于2006-01-26 09:21
    可以用群论证明:如果有k个人不在自己的位置上,那么要且仅要k的代价,即可使这些人归位

    剩下的..很简单了吧...

    0

    回复 lemon_cn发表于2008-08-08 15:55
    热烈庆祝用pascal AC的第二题~
    p.s.我是C++的~~

  • -1
    @ 2015-07-05 11:02:04

    0

    回复 yingjiangyu发表于2015-02-15 21:55
    打‘Wrong!’有50分。。

    0

    回复 东大微雕发表于2015-02-07 15:20
    这道题真是太好了。奇妙无穷。
    #include<iostream>
    #include<string.h>
    #include<stdio.h>
    using namespace std;
    int a[50005];
    int size;
    void go(){
    int i, j;
    int ans = 0;
    int dis[50005];
    memset(dis, 0, sizeof(dis));
    for (i = 1; i <= size; i++){
    int d = (a[i] - i + size) % size;
    dis[d]++;
    }
    for (i = 0; i < size; i++){
    if (ans < dis[i])
    ans = dis[i];
    }
    memset(dis, 0, sizeof(dis));
    for (i = 1; i <= size; i++){
    int d = (a[size+1-i]-i+size) % size;
    dis[d]++;
    }
    for (i = 0; i < size; i++){
    if (ans < dis[i])ans = dis[i];
    }
    cout << size-ans << endl;
    }
    int main(){
    freopen("in.txt", "r", stdin);
    int neibor[50005][2];
    int i;
    cin >> size;
    for (i = 1; i <= size; i++){
    scanf("%d%d",&neibor[i][0],& neibor[i][1]);
    }
    bool used[50005];
    memset(used, 0, sizeof(used));
    a[1] = 1;
    used[1] = true;
    for (i = 2; i <= size; i++){
    int last = a[i - 1];
    if (!used[neibor[last][0]]){
    a[i] = neibor[last][0];
    used[a[i]] = true;
    }
    else if (!used[neibor[last][1]]){
    a[i] = neibor[last][1];
    used[a[i]] = true;
    }
    else {
    cout << -1 << endl;
    return 0;
    }
    }

    if (neibor[1][0] != a[size] && neibor[1][1] != a[size]){
    cout << -1 << endl;
    return 0;
    }
    go();
    return 0;
    }

    0

    回复 3516发表于2014-07-30 08:59
    include<stdio.h>

    include<string.h>

    int data[50001][2],shi[50001],a[50001];
    int main()
    {
    int n,i,j,qian,hou; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d%d",&data[i][0],&data[i][1]); } a[1]=1;shi[a[1]]=1 for(i=2;i<=n;i++) { qian=data[a[i-1]][0]; hou=data[a[i-1]][1]; if(shi[qian]==0) { a[i]=qian; shi[qian]=1; } else if(shi[hou]==0) { a[i]=hou; shi[hou]=1; } else { printf("-1"); return 0; } } int temp=0,max=0; memset(shi,0,sizeof(shi)); for(i=1;i<=n;i++) { temp=(n+a[i]-i+1)%n; shi[temp]++; } for(i=0;i<n;i++) { if(max<shi[i]) { max=shi[i]; } } memset(shi,0,sizeof(shi)); for(i=1;i<=n;i++) { temp=(n+a[n-i+1]-i+1)%n; shi[temp]++;
    }
    for(i=0;i<n;i++)
    {
    if(max<shi[i])max=shi[i];
    }
    printf("%d",n-max);
    }

    0

    回复 S.Y.F发表于2013-08-31 14:04
    题解
    1111111129回复于2014-08-13 11:52
    orzorzorz

    0

    回复 S.Y.F发表于2013-07-29 16:55
    从10、到30、到100。。。。。。
    题解:http://blog.163.com/syf_light_feather/blog/static/223755067201362945326756/

    0

    回复 vcvycy发表于2013-06-30 00:56
    20 30 40 50 70 分都有~泪流满面.
    Accepted

    100
    772 2

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:55:05
    Wrong Answer

    70
    613 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:53:24
    Wrong Answer

    70
    686 2

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:45:35
    Wrong Answer

    70
    856 2

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:42:12
    Wrong Answer

    70
    803 2

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:37:26
    Wrong Answer

    70
    882 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:22:39
    Wrong Answer

    70
    1145 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:20:30
    Wrong Answer

    10
    733 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:11:30
    Wrong Answer

    50
    723 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-30 00:04:20
    Wrong Answer

    50
    781 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:55:49
    Wrong Answer

    40
    656 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:49:49
    Wrong Answer

    40
    758 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:44:00
    Time Exceeded

    30
    7160 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:38:22
    Time Exceeded

    20
    7135 1

    P1008 篝火晚会
    vcvycy Pascal 2013-06-29 23:35:08

    0

    回复 SEX丶Elope发表于2013-02-16 10:10
    点击查看程序源码+详细题解
    cuichen回复于2014-09-09 09:24
    怎么又是你??你有什么企图?骗访问量???垃圾!

    0

    回复 qyjubriskxp发表于2010-07-09 21:31
    再一次体会到c++流的悲剧,秒杀和3s原来只是输入方式的不同,杯具~~
    yuyilahanbao回复于2014-01-24 11:47
    从c转到c++第一次不AC(除去忘记把语言有c改为c++的)就是因为c++输入输出的问题
    从那次起,我的c++的输入都是用scanf和printf了
    因为
    保险
    安全
    我记不清cin是<<还是>>
    printf和scanf相对更灵活
    ....

    0

    回复 slm发表于2010-03-16 18:27
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    嘿嘿

    0

    回复 superyoi发表于2009-11-10 11:50

    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    superyoi killed p1008 with a headshot by awp

    0

    回复 200853349发表于2009-11-10 10:49
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    当我看到众位神牛打出“置换群”三个字后,我在黑书百度GOOGLE维基百科逛了得有一个半小时多然后回来AC了。。。

    思路和strini神牛的基本一样。

    0

    回复 sinb发表于2009-11-09 13:02
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    其实很简单,不要想复杂了,先是想办法构成,然后用置换群的方法即可ac。

    0

    回复 香蕉派发表于2009-11-06 11:29
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    虽然不懂什么叫置换群,但是思路还是很清晰的。。

    0

    回复 赏金神侠PPF发表于2009-11-05 11:45
    一星星纪念~

    0

    回复 strini发表于2009-10-30 22:11
    根据群论原理,任何置换群都可以分解为若干个循环节。显然,这道题目就是冲着这点来的。因为如果某循环的长度为L,那么本题中只需要代价为L的操作。注意,这里的L!=1,这是因为只有一个人的循环节不需要任何代价的操作。到这里才只能拿三十分,因为圈是可以旋转的,常规方法需要O(n^2)才能解决。不妨这里以编号为1的人为基准,定义每个人到自己应该所在位置的距离。距离不超过n-1。可以通过最大值来寻找能在自己位置上的最多的人数(因为距离为x的人在旋转x次后转到自己的位置上),那么在比较好的情况下,可以优化到O(n)。

    TIME: 1H
    SUBMIT:
    1 70 Error: 发现希望相邻是不精确的,于是改了个搜索方向。(以为题目给定的是按照左右方向,白书说过不能“假定”!)。
    2 90 Error: 终于明白要取两个搜索方向的最大值。
    3 Accepted.


    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 skykey发表于2009-10-29 17:58
    #include<iostream>
    using namespace std;
    int n;
    int a[50001],b[50001],c[50001];
    int aim[50001];
    void G_MAP()
    {
    bool mark[50001]={false};
    int p=1,r=1;
    while(p<=n)
    {
    aim[p]=r;mark[r]=true;p++;
    if(!mark[a[r]])r=a[r];
    else if(!mark[b[r]])r=b[r];
    else if(p<=n){cout<<-1;exit(0);}
    }
    }
    int COMPULATE()
    {
    int max=0;
    int t;
    int record[2][50001];
    for(int i=1;i<=n;i++)record[0][i]=record[1][i]=0;
    for(int i=1;i<=n;i++)
    {
    if((t=aim[i]-i)<0)t+=n;
    record[0][t]++;
    if(record[0][t]>max)max=record[0][t];
    if((t=aim[i]-(n+1-i))<0)t+=n;
    record[1][t]++;
    if (record[1][t]>max)max=record[1][t];
    }
    return max;
    }
    int main()
    {
    cin>>n;
    for(int i=1;i<=n;i++)
    {scanf("%d%d",&a[i],&b[i]);c[a[i]]++;c[b[i]]++;}
    for(int i=1;i<=n;i++)if(c[i]!=2){cout<<-1;return 0;}

    G_MAP();
    int T=COMPULATE();
    cout<<n-T;
    }

    0

    回复 song19931218发表于2009-10-27 20:11
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    考虑两种情形(貌似这两种情形很像,但又真的不同,后来才想起,在化学的手性碳原子那部分遇到过类似情况。。。)
    然后就是运用置换群的知识

    0

    回复 Aries_C发表于2009-10-25 08:24
    正反两遍...两遍...<幽幽的声音飘远..>

    不然就是70分啊...

    不看题解的情况下竟然自己想到了...

    记得以前老师给我们做过这题的..细节什么的现在做又忘记了..唉..

    0

    回复 国防安全员001发表于2009-10-21 22:00
    Flag   Accepted
    题号   P1008
    类型(?)   模拟
    通过   1701人
    提交   4835次
    通过率   35%
    难度   3

    题目表述有问题。。

    0

    回复 liubosen发表于2009-10-21 21:50
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    yaaaayyayayyayayayayayayayayayayayayayayayyaayayayayayayyaayayayay
    var
    n,max,i:longint;
    a,b,c,d:array[0..50001] of longint;
    begin
    readln(n);
    for i:=1 to n do
    readln(a[i],b[i]);
    c[1]:=1;
    c[2]:=a[1];
    for i:=3 to n do
    if c=a[c] then c[i]:=b[c]
    else
    if c=b[c] then c[i]:=a[c]
    else begin
    writeln(-1);
    halt
    end;
    if c[n]<>b[1] then
    begin
    writeln(-1);
    halt
    end;
    fillchar(d,sizeof(d),0);
    for i:=1 to n do
    inc(d[(c[i]-i+n)mod n]);
    for i:=0 to n-1 do
    if d[i]>max then max:=d[i];
    fillchar(d,sizeof(d),0);
    for i:=1 to n do
    inc(d[(c[i]+i-1)mod n]);
    for i:=0 to n-1 do
    if d[i]>max then max:=d[i];
    writeln(n-max);
    end.

    0

    回复 lishunzhi发表于2009-10-21 00:11
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    置换群,但建环是重点

    0

    回复 zebra发表于2009-10-03 09:48
    #include <iostream>
    #include <cassert>
    using namespace std;
    long N,seq[50001],p=1;
    class
    {
    private:
    long nbr[50001][3];
    bool flag[50001];
    bool isnbr(long v1,long v2)
    {
    for(int i=1;i<=nbr[v1][0];i++)
    if(nbr[v1][i]==v2)
    return true;
    return false;
    }
    public:
    bool AddE(long v1,long v2)
    {
    if(isnbr(v1,v2))
    return true;
    else
    if(nbr[v1][0]==2||nbr[v2][0]==2)
    return false;
    else
    {
    nbr[v1][++nbr[v1][0]]=v2;
    nbr[v2][++nbr[v2][0]]=v1;
    return true;
    }
    }
    void dfs(long i)
    {
    assert(!flag[i]);
    flag[i]=true,seq[p++]=i;
    for(int j=1;j<=nbr[i][0];j++)
    {
    if(!flag[nbr[i][j]])
    {
    dfs(nbr[i][j]);
    break;
    }
    }
    }
    }G;
    long solve()
    {
    long cnt1[50001]={0},cnt2[50001]={0},ans=0;
    for(int i=1,a,b;i<=N;i++){
    a=seq[i]-i;
    if(a<0) a+=N;
    b=seq[i]-(N+1-i);
    if(b<0) b+=N;
    if(++cnt1[a]>ans) ans=cnt1[a];
    if(++cnt2>ans) ans=cnt2;
    }
    return N-ans;
    }
    int main()
    {
    cin >> N;
    for(int i=1,nbr1,nbr2;i<=N;i++)
    {
    cin >> nbr1 >> nbr2;
    if(!G.AddE(i,nbr1)||!G.AddE(i,nbr2))
    {
    cout << -1 << endl;
    return 0;
    }
    }
    G.dfs(1);
    cout << solve() << endl;
    system("pause");
    return 0;
    }

    0

    回复 -117-Join发表于2009-09-18 21:29
    哪位大牛帮忙看看我错哪里了
    它只得90分
    program fire;
    type
    arr=record
    l,r:longint;
    end;
    var
    num:array[1..50000]of longint;
    a:array[1..50000]of arr;
    b:array[1..50000]of longint;
    i,k,j,n:longint;
    begin
    readln(n);
    for i:=1 to n do
    readln(a[i].l,a[i].r);
    b[1]:=1;
    b[n]:=a[1].l;
    if a[b[n]].l=b[1]then b[n-1]:=a[b[n]].r
    else b[n-1]:=a[b[n]].l;
    i:=n-1;
    b[2]:=a[1].r;
    j:=2;
    while j<=i do
    begin
    if b<>a[b[i]].l then b:=a[b[i]].l
    else b:=a[b[i]].r;
    dec(i);
    if b[j-1]<>a[b[j]].r then b[j+1]:=a[b[j]].r
    else b[j+1]:=a[b[j]].l;
    inc(j);
    end;
    for i:=2 to n-1 do
    if(b<>a[b[i]].r)and(b<>a[b[i]].l)or(b<>a[b[i]].r)and(b<>a[b[i]].l)then
    begin
    write(-1);
    halt
    end;
    if(b[n]<>a[b[1]].l)and(b[n]<>a[b[1]].r)or(b[2]<>a[b[1]].l)and(b[2]<>a[b[1]].r)or(b[1]<>a[b[n]].l)and(b[1]<>a[b[n]].r)or(b[n-1]<>a[b[n]].l)and(b[n-1]<>a[b[n]].r)then
    begin
    write(-1);
    halt
    end;
    num[0]:=0;
    for i:=1 to n do
    begin
    a[b[i]].l:=i;
    num[i]:=0;
    end;
    for i:=1 to n do
    if a[i].l-i>=0 then inc(num[a[i].l-i])
    else inc(num[a[i].l-i+n]);
    j:=0;
    for i:=0 to n do
    if num[i]>j then j:=num[i];
    write(n-j);
    end.
    写的有点长

    0

    回复 fs302发表于2009-09-17 20:13
    分析:学一个好思想:正难则反!由顺序到乱序我们很难快速找到,但是我们知道如何从乱序变为顺序!解决本题利用了组合数学中置换群的思想。

    从第一个人处断开,将圆环的问题转化为序列的问题。如果可以,求出目标序列。求出目标序列复杂度O(n).
    求出目标序列右移0至n-1位置时,不需要移动的人数。将目标序列反转,再求出目标序列右移0至n-1位置时,不需要移动的人数。求不需要移动的人数最大等价于求需要移动的人数最小。复杂度O(n)。
    更详细的说:
    引进“相对有序”这个概念,当两个人满足C[j]-C[i]==j-i时,两个相对有序。
    题目要求最小的总代价,但是我们可以考虑倒过来想,要求最小的总代价亦即求最多有多少人不用移动,亦即相对有序。
    然后我们引进一个辅助变量T=C-I,{C-I>=0},T=C[i]-I+N,{C[i]-I<0},那么这个T[i]有什么意义呢?我们知道初始状态的编号是1-N,而目标状态是C[1]-C[N],那么C-I便是从目标状态到初始状态顺时针所要移动的距离,那么如果那么T值相等的两个同学则是相对有序的,亦即不用移动,我们只要找出最大的T然后N-Max(T)就是得到的结果,但是这样还不够,因为刚刚那样只是顺时针所要移动的距离,我们还要计算逆时针的到的结果,从顺时针和逆时针中找到最大的T,然后N-Max(T)才能够是正确结果.

    0

    回复 maxint64发表于2009-09-01 21:33
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    先是物理大发了——以为 b1,b2...bm是连续的
    看了牛们的题解 一次ac :)

    0

    回复 柔情使者发表于2009-08-20 15:44
    第一遍做的时候没有看题解,自己测了好几遍总是60分,看了n多大牛的解释才恍然大悟,竟然要正反两遍!!!唉,幸亏咱有测试数据,否则我可就惨了...
    O(n)的求目标队列算法,都说是冒泡排序,我没看出来,倒是有点像。

    0

    回复 maxiem发表于2009-08-18 20:55
    物理自重啊,嘿嘿。
    注意要正反两遍哦~
    9MS?
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 9ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:9ms

    (好像那个冒泡是口胡,大家不要被那个蒙了

    program fire;
    var
    st:array [1..50000,1..2] of longint;
    k,final:array [0..50000] of longint;
    ex:array [1..50000] of boolean;
    p,max,i,n:longint;
    begin
    fillchar (st,sizeof(st),0);
    fillchar (ex,sizeof(ex),0);
    fillchar (final,sizeof(final),0);
    fillchar (k,sizeof(k),0);
    readln (n);
    for i:=1 to n do readln (st,st);
    final[1]:=1;p:=2;ex[1]:=true;
    for i:=1 to n do begin
    if ex[st[final[i],1]]=false then begin
    final[p]:=st[final[i],1];
    ex[st[final[i],1]]:=true;
    inc(p);
    end
    else if ex[st[final[i],2]]=false then begin
    final[p]:=st[final[i],2];
    ex[st[final[i],2]]:=true;
    inc(p);
    end;
    end;
    if p-1<>n then begin
    writeln (-1);
    halt;
    end;
    max:=0;
    for i:=1 to n do if final[i]>=i then inc(k[final[i]-i]) else inc(k[n-i+final[i]]);
    for i:=0 to n-1 do if k[i]>max then max:=k[i];
    fillchar (k,sizeof(k),0);
    for i:=n downto 1 do if final[i]>=n-i+1 then inc(k[final[i]-n+i-1]) else inc(k[final[i]+i-1]);
    for i:=0 to n -1 do if k[i]>max then max:=k[i];
    writeln (n-max);
    end.

    0

    回复 suning发表于2009-08-14 09:43
    啊呜~
    一年前误解了题意~
    一年后理解了题意~
    然后就是1次美妙的AC

    PS:[误]解[理]解~~~[物理]?

    0

    回复 fengwuliu发表于2009-08-13 17:20
    lgxcgd说的太对了!太感谢了5555

    0

    回复 Matt发表于2009-08-11 22:28
    NOIP也会考高等数学...

    由于原图是环,所以置换群可表示为一次循环。作差是个好方法。

    但求冒泡排序是怎么作的

    0

    回复 3830372发表于2009-08-11 21:28
    Flag   Accepted
    题号   P1008
    类型(?)   模拟
    通过   1504人
    提交   4282次
    通过率   35%
    难度   3

    提交 讨论 题解 状态

    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 尖端才子发表于2009-08-11 11:14
    纪念一下……第1500个AC……

    Flag    Accepted
    题号   P1008
    类型(?)   模拟
    通过   1500人
    提交   4274次
    通过率   35%
    难度   3

    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 SecretAgent发表于2009-08-10 14:02
    置换群是正解

    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 yangbei发表于2009-08-07 14:57
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 338ms
    ├ 测试数据 05:答案正确... 322ms
    ├ 测试数据 06:答案正确... 306ms
    ├ 测试数据 07:答案正确... 338ms
    ├ 测试数据 08:答案正确... 338ms
    ├ 测试数据 09:答案正确... 322ms

    ├ 测试数据 10:答案正确... 306ms

    Accepted 有效得分:100 有效耗时:2270ms

    算镜像时偷了点懒,不过也算一遍AC了

    0

    回复 ja_son发表于2009-08-06 15:44
    a:拆环成队,寻求目标队列。
    b:b1,b2...bm不是连续的,而且是任意的。只要有成立目标队列,与原来的队列相匹配就可以知道有多少(设为n个)需要移动位置,则代价就是n。
    c:目标队列有多种情况,可以反转,也可以左右移动。

    0

    回复 1s发表于2009-08-03 17:56

    如对本题有疑问可以参看我的题解:
    http://xujieqi.blog.hexun.com/35722312_d.html

    0

    回复 DMKaplony发表于2009-07-30 15:15
    当时的时间限制好像是2s。。有个题解说把1定为第一项然后进行冒泡排序。。不过这里是1s 啊。。。也行只有置换群了吧。

    0

    回复 xusc_2009发表于2009-07-28 14:30
    看不懂,只好搁浅
    什么时候想清楚了再做

    0

    回复 董发表于2009-07-24 19:11
    program p1008;
    var i,n,k,j,sum1,sum2,ans,max:longint;
       a,b,w,d,c:array[0..50005] of longint;

    begin
    readln(n);
    for i:=1 to n do
    readln(a[i],b[i]);
    w[1]:=1; w[2]:=a[w[1]];
    k:=1;

    repeat
    inc(k);
    if w[k-1]=a[w[k]] then w[k+1]:=b[w[k]]
      else if w[k-1]=b[w[k]] then w[k+1]:=a[w[k]]
       else begin
           writeln(-1);
           exit;
           end;
    until k=n;
    if w[n+1]<>w[1] then
           begin
           writeln(-1);
           exit;
           end;

    for i:=1 to n do
    begin
    a[i]:=w[i]-i;
    b[i]:=w[n-i+1]-i;
    if a[i]<0 then a[i]:=a[i]+n;
    if b[i]<0 then b[i]:=b[i]+n;
    inc(c[a[i]]);
    inc(d[b[i]]);
    end;
    for i:=0 to n-1 do
    begin
    if ans<c[i] then ans:=c[i];
    if ans<d[i] then ans:=d[i];
    end;
    writeln(n-ans);  
    end.

    0

    回复 我飞发表于2009-07-23 21:00
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 93狒狒发表于2009-07-23 20:59
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    秒杀......

    0

    回复 fjxmlhx发表于2009-07-22 13:15
    置换群,做2n次,顺时针和逆时针.
    对于一个置换,最小操作费用是所有循环长度的和.因此实际上是找出2n个置换中哪个置换循环长度为1的数量最多.

    0

    回复 340508965发表于2009-07-21 15:01
    ⊙﹏⊙b汗
    不知道的以为这是数学竞赛......
    ...
    我的数论与图论可以说脑袋里空白一片.........
    怎么办,我的竞赛啊
    ........

    算了 看了题解 大家写的
    总算弄懂这道题了
    先前以为b1,b2,b3..bm是连续的
    没想到是任意的!!!!!!!!!

    诶 叹悲歌未切 为撼奈何编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    总算AC了


    program p1008;
    var i,n,k,j,sum1,sum2,ans,max:longint;
    a,b,w,d,c:array[0..50005] of longint;

    begin
    readln(n);
    for i:=1 to n do
    readln(a[i],b[i]);
    w[1]:=1; w[2]:=a[w[1]];
    k:=1;

    repeat
    inc(k);
    if w[k-1]=a[w[k]] then w[k+1]:=b[w[k]]
    else if w[k-1]=b[w[k]] then w[k+1]:=a[w[k]]
    else begin
    writeln(-1);
    exit;
    end;
    until k=n;
    if w[n+1]<>w[1] then
    begin
    writeln(-1);
    exit;
    end;

    for i:=1 to n do
    begin
    a[i]:=w[i]-i;
    b[i]:=w[n-i+1]-i;
    if a[i]<0 then a[i]:=a[i]+n;
    if b[i]<0 then b[i]:=b[i]+n;
    inc(c[a[i]]);
    inc(d[b[i]]);
    end;
    for i:=0 to n-1 do
    begin
    if ans<c[i] then ans:=c[i];
    if ans<d[i] then ans:=d[i];
    end;
    writeln(n-ans);
    end.

    0

    回复 zsy90943发表于2009-07-18 00:51
    构造巧妙、、看来还是要学好数论和图论额、、、、

    0

    回复 POM无敌牛B发表于2009-07-16 11:47
    编译通过...
    ├ 测试数据 01:运行超时...
    ├ 测试数据 02:运行超时...
    ├ 测试数据 03:运行超时...
    ├ 测试数据 04:运行超时...
    ├ 测试数据 05:运行超时...
    ├ 测试数据 06:运行超时...
    ├ 测试数据 07:运行超时...
    ├ 测试数据 08:运行超时...
    ├ 测试数据 09:运行超时...

    ├ 测试数据 10:运行超时...

    Unaccepted 有效得分:0 有效耗时:0ms
    无奈 哪位哥哥救救我

    0

    回复 yxy发表于2009-06-16 18:16
    把置换解释成度为2图,真有才.
    求出序列,正反分别做一次差就行了.

    0

    回复 sxpeter发表于2009-06-14 16:56
    讲建环吧。数组w表示环,我用的是一种类似并查集的方法。
    begin
    read(n);
    for i:=1 to n do read(a[i],b[i]);
    t:=2;w[1]:=1;w[2]:=a[1];
    while true do begin
    if a[w[t]]<>w[t-1]then w[t+1]:=a[w[t]]//是否在左边
    else if b[w[t]]<>w[t-1]then w[t+1]:=b[w[t]]//是否在右边
    else begin writeln(-1);halt;end;//失败判断
    inc(t);
    if t>n then break;
    end;
    if w[n+1]<>w[1]then begin writeln(-1);halt;end;//本句一定要加!!!!!!
    end.

    0

    回复 lgxcgd发表于2009-05-17 20:24
    首先把这个圈看做一个图,每个同学看做一个顶点。因为要形成环,所以每个顶点的度必须为2。

    如果存在度数不为2的顶点,那么整个图无法构成一个环,即“无论怎么调整都不能符合每个同学的愿望”输出-1。

    如果是一个环,那么就遍历图,生成以第1个顶点为开头的序列。现在就要求出最小移动的代价。

    在理解题意所述的调整方式中,要注意实际上就是把M个在错误位置上的人移动到正确的位置上,代价为M。一次下令移动即可。

    假如生成的目标序列为1,5,3,2,4。我们现在就需要比较它和初始状态1,2,3,4,5,看有几个人离开了原来的位置。但这个序列实际代表的是一个环,而且方向正反有两种,就需要把初始序列正反分别转N次,和得到的序列比较,看其中最少有几个位置上的人编号不相同,就得到了我们要求的最小代价。

    上述方法有大量冗余。但可以发现转来转去不管怎么转,任意两个人之间的相对位置关系在这过程中都不会变。于是想到做差,如果差小于0则加上N。

    1 5 3 2 4

    - 1 2 3 4 5

    0 3 0 3 4
    这表示序列1,5,3,2,4不转动时1,3两个人在原来的位置上,转动3个位置后5和2两个人在原来的位置上,转动4个位置后只有4一个人会在原来的位置上。这就是说,1,5,3,2,4与1,2,3,4,5在旋转后最多有2个位置上的人编号相同,即最少有3个位置上的人编号不相同。同理要反转再求一次。

    记录每个不同的差值的个数,取其最大值P,即不调换次数最大的。结果N-P就是调换次数最小的。

    0

    回复 src250发表于2009-05-14 08:27

    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    切记:重新构图时一定要对数组清空!我的第一次只有50分,就是这个原因!

    0

    回复 love19960108发表于2009-04-26 17:59
    这题可以用C++这样做么??
    #include <iostream>
    #include <cassert>
    using namespace std;
    long N,seq[50001],p=1;
    class{
    private:
    long nbr[50001][3];
    bool flag[50001];
    bool isnbr(long v1,long v2){
    for(int i=1;i<=nbr[v1][0];i++)
    if(nbr[v1][i]==v2) return true;
    return false;
    }
    public:
    bool AddE(long v1,long v2){
    if(isnbr(v1,v2)) return true;
    else if(nbr[v1][0]==2||nbr[v2][0]==2) return false;
    else{
    nbr[v1][++nbr[v1][0]]=v2;
    nbr[v2][++nbr[v2][0]]=v1;
    return true;
    }
    }
    void dfs(long i){
    assert(!flag[i]);
    flag[i]=true,seq[p++]=i;
    for(int j=1;j<=nbr[i][0];j++){
    if(!flag[nbr[i][j]]){
    dfs(nbr[i][j]);
    break;
    }
    }
    }
    }G;
    long solve(){
    long cnt1[50001]={0},cnt2[50001]={0},ans=0;
    for(int i=1,a,b;i<=N;i++){
    a=seq[i]-i;
    if(a<0) a+=N;
    b=seq[i]-(N+1-i);
    if(b<0) b+=N;
    if(++cnt1[a]>ans) ans=cnt1[a];
    if(++cnt2>ans) ans=cnt2;
    }
    return N-ans;
    }
    int main(){
    cin >> N;
    for(int i=1,nbr1,nbr2;i<=N;i++){
    cin >> nbr1 >> nbr2;
    if(!G.AddE(i,nbr1)||!G.AddE(i,nbr2)){
    cout << -1 << endl;
    return 0;
    }
    }
    G.dfs(1);
    cout << solve() << endl;
    return 0;
    }

    0

    回复 voyagec2发表于2009-03-18 15:53
    难理解,不过算法很精妙

    0

    回复 pRoevollove发表于2009-02-25 23:49
    天,把(p[i]-i+n)mod n理所当然地打成了abs(p[i]-i)
    结果一直50分……还一直以为自己构造错了……

    ps 我可以过楼下的范例哦

    0

    回复 ufo172849z发表于2009-01-24 23:05
    ms楼下的程序不能处理这种反例(测试数据还是不够强啊)
    6
    2 3
    1 3
    1 2
    5 6
    4 6
    4 5
    应该输出-1的吧?因为是两个环

    var a,b:array[0..50000]of longint;
    c:array[0..50000,1..2]of longint;
    d:array[0..50000]of boolean;
    i,j,k,m,n,max:longint;
    can:boolean;

    begin
    readln(n);
    for i:=1 to n do
    readln(c,c);
    b[0]:=c[1,1]; b[n]:=c[1,1];
    fillchar(d,sizeof(d),0);
    k:=1;
    can:=true;
    for i:=1 to n-1 do
    begin
    if d[k] then can:=false;
    b[i]:=k; d[k]:=true;
    if b=c[k,1] then k:=c[k,2]
    else if b=c[k,2] then k:=c[k,1]
    else can:=false;
    if not can then break;
    end;
    if can then
    if b[n]<>k then can:=false;
    if can then
    begin
    max:=-1;
    fillchar(a,sizeof(a),0);
    for i:=1 to n do
    inc(a[(b[i]-i+n) mod n]);
    for i:=0 to n-1 do
    if a[i]>max then max:=a[i];
    fillchar(a,sizeof(a),0);
    for i:=1 to n do
    inc(a[(b[n-i+1]-i+n)mod n]);
    for i:=1 to n-1 do
    if a[i]>max then max:=a[i];
    writeln(n-max);
    end
    else
    writeln(-1);
    end.

    0

    回复 tangdongjian发表于2009-01-23 22:17
    我在做镜像时把原先max直接覆盖上了,注意

    0

    回复 永恒888发表于2009-10-26 22:50
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 tangkunjie发表于2009-06-04 19:50
    挺烦人的题目

    0

    回复 ykspeter发表于2008-11-13 20:32
    program fire(input,output);
    var
    n,i,j,k,max,v:longint;
    a:array[0..100000,1..2] of longint;
    b,c:array[0..100000] of longint;
    begin
    readln(n);
    for i:=1 to n do readln(a,a);
    for i:=1 to n do
       begin
        k:=0;
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if (k=4) or (k=3)
        then begin
           writeln('-1');
           exit
           end
       end;
    b[1]:=1;i:=2;k:=a[1,1];j:=1;
    repeat
      b[i]:=k;
      inc(i);
      v:=k;
      if a[k,1]<>j
      then k:=a[k,1]
      else k:=a[k,2];
      j:=v;
    until i=n+1;
    fillchar(c,sizeof(c),0);
    for i:=1 to n do inc(c[(b[i]-i+n)mod n]);
    for i:=0 to n-1 do
       if c[i]>max
       then max:=c[i];
    fillchar(c,sizeof(c),0);max:=0;
    for i:=1 to n do inc(c[(b[n-i+1]-i+n)mod n]);
    for i:=n-1 downto 0 do
       if c[i]>max
       then max:=c[i];
    writeln(n-max);
    end.

    0

    回复 getuojian发表于2008-11-10 13:38
    #include<stdio.h>
    #include<memory.h>

    const int maxn=50010;
    int n;
    int f[maxn][2];
    int goal[maxn];
    int ans=maxn;
    int hash[maxn];

    bool SET_ORI(){
    bool flag[maxn];
    memset(flag, true, sizeof(flag));
    goal[1]=1; flag[1]=false;
    for (int i=1; i<=n-1; i++){
    if (flag[f[goal[i]][0]]){
    goal=f[goal[i]][0];
    flag[f[goal[i]][0]]=false;
    continue;
    }
    if (flag[f[goal[i]][1]]){
    goal=f[goal[i]][1];
    flag[f[goal[i]][1]]=false;
    continue;
    }
    return false;
    }
    if ((goal[n]!=f[1][0]) && (goal[n]!=f[1][1]))
    return false;
    return true;
    }
    int SWAP(int i, int j){
    int t=goal[i];
    goal[i]=goal[j];
    goal[j]=t;
    return 0;
    }

    int min(int i, int j){
    return i>j?j:i;
    }
    int HASH(){
    for(int i=1; i<=n; i++)
    hash[i]=goal[i]-i+n;
    return 0;
    }

    int CALC(){
    int temp[maxn*2], back=0;
    memset(temp, 0, sizeof(temp));
    for (int i=1; i<=n; i++)
    temp[hash[i]%n]++;
    for (int i=1; i<=2*n-1; i++)
    if (temp[i] > back)
    back=temp[i];
    return back;
    }

    int main(){
    freopen("fire.in", "r", stdin);
    freopen("fire.out", "w", stdout);
    scanf("%d", &n);
    for (int i=1; i<=n; i++)
    scanf("%d %d", &f[i][0], &f[i][1]);
    if (!SET_ORI()){
    printf("-1");
    return 0;
    }
    //forward
    HASH();
    ans=min(ans, n-CALC());
    //backward
    for (int i=1; i<=n/2; i++)
    SWAP(i,n-i+1);
    HASH();
    ans=min(ans, n-CALC());

    printf("%d", ans);
    return 0;
    }

    0

    回复 IVORY发表于2008-11-06 10:46
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    CHEAT的...

    0

    回复 storey p发表于2008-11-05 14:19
    回447389831:
    exit换成halt

    0

    回复 FenXy发表于2008-11-04 08:28
    艺术p245

    0

    回复 hlq发表于2008-11-01 14:31
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms
    ├ 测试数据 10:答案正确... 0ms

    求不在位置上的人数
    a【i】 第i位上的同学编号
    for i:=1 to n do
    begin
    inc(b[(a[i]-i+n) mod n])
    end;
    max:=0;
    for i:=0 to n-1 do
    if b[i]>max then max:=b[i];
    fillchar(b,sizeof(b),0);
    for i:=1 to n do
    begin
    inc(b[(a[i]-(n-i+1)+n)mod n]);//对称
    end;
    for i:=0 to n-1 do
    if b[i]>max then max:=b[i];

    0

    回复 Will~骷髅发表于2008-10-30 21:37
    编译通过...
    ├ 测试数据 01:运行超时...
    ├ 测试数据 02:运行超时...
    ├ 测试数据 03:运行时错误...|错误号: -1073741819
    ├ 测试数据 04:运行时错误...|错误号: -1073741819
    ├ 测试数据 05:运行时错误...|错误号: -1073741819
    ├ 测试数据 06:运行时错误...|错误号: -1073741819
    ├ 测试数据 07:运行时错误...|错误号: -1073741819
    ├ 测试数据 08:运行时错误...|错误号: -1073741819
    ├ 测试数据 09:运行时错误...|错误号: -1073741819

    ├ 测试数据 10:运行时错误...|错误号: -1073741819

    Unaccepted 有效得分:0 有效耗时:0ms

    怎么会这样???

    0

    回复 悲伤逆流成河发表于2008-10-28 22:13
    #include <iostream>
    #include <fstream>
    using namespace std ;

    int hash[50001];
    int n , i , j , t , maxs(0) ;

    inline void HASH ( int e[] )
    {
    for ( i = 1 ; i <= n ; i++ )
    {
    e[i] -= i ;
    if ( e[i] < 0 ) e[i] += n ;
    hash[e[i]]++ ;
    }
    for ( i = 0 ; i < 50001 ; i++ )
    if ( maxs < hash[i] ) maxs = hash[i] ;
    }

    int main(){
    ifstream fin ("fire.in") ;
    ofstream fout ("fire.out") ;

    fin >> n ;
    int e[n+1] , h[n+1][2] , e2[n+1];
    bool f[n+1] ;
    for ( i = 1 ; i <= n ; i++ )
    {
    f[i] = false ;
    fin >> h[i][0] >> h[i][1] ;
    }
    e[1] = 1 ;
    f[1] = true ;
    for ( i = 2 ; i <= n ; i++ )
    {
    if ( e < 0 ) { fout << -1 << endl ; exit(0) ; }
    if ( !f [ h[ e ][0] ] ) e[i] = h[ e ][0] ;
    if ( !f [ h[ e ][1] ] ) e[i] = h[ e ][1] ;
    f[ e[i] ] = true ;
    }
    for ( i = 1 , j = n ; i <= n ; i++,j-- ) e2[j] = e[i] ;
    HASH ( e ) ;
    memset ( hash , 0 , sizeof ( hash ) ) ;
    HASH ( e2 ) ;
    fout << n - maxs << endl ;
    }

    0

    回复 evelynhe发表于2008-10-26 16:31
    “置换群思想...今天刚明白...

    先构造新数列(要构造两次,否则只有70分),然后向右计算相对位置差,然后累加记录数组,然后用N减去相对位置差累加值最大的,就是答案... ”

    这是真的

    0

    回复 true1023发表于2008-10-25 09:32
    置换群的基本概念
    利用原序列和目标序列每个元素的绝对位置差来求出原序列每个元素对于目标序列的相对位置,找相对位置相同的最多的元素数,用总元素数减去它即为结果。

    0

    回复 447389831发表于2008-10-21 09:45
    program fire(input,output);
    var
    n,i,j,k,max,v:longint;
    a:array[0..100000,1..2] of longint;
    b,c:array[0..100000] of longint;
    begin
    readln(n);
    for i:=1 to n do readln(a,a);
    for i:=1 to n do
       begin
        k:=0;
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if a[a,1]<>i then inc(k);
        if a[a,2]<>i then inc(k);
        if (k=4) or (k=3)
        then begin
           writeln('-1');
           exit
           end
       end;
    b[1]:=1;i:=2;k:=a[1,1];j:=1;
    repeat
      b[i]:=k;
      inc(i);
      v:=k;
      if a[k,1]<>j
      then k:=a[k,1]
      else k:=a[k,2];
      j:=v;
    until i=n+1;
    fillchar(c,sizeof(c),0);
    for i:=1 to n do inc(c[(b[i]-i+n)mod n]);
    for i:=0 to n-1 do
       if c[i]>max
       then max:=c[i];
    fillchar(c,sizeof(c),0);max:=0;
    for i:=1 to n do inc(c[(b[n-i+1]-i+n)mod n]);
    for i:=n-1 downto 0 do
       if c[i]>max
       then max:=c[i];
    writeln(n-max);
    end.
    90 分,牛人门帮看下把

    0

    回复 cnfnje1发表于2008-10-17 18:12
    置换群.....是什么?
    readln(n);
    for i:=1 to n do readln(a[i],b[i]);
    c[1]:=1; c[2]:=a[1];
    for i:=3 to n do if c=a[c] then c[i]:=b[c]
    else if c=b[c] then c[i]:=a[c]
    else begin writeln(-1); halt end;
    if c[n]<>b[1] then begin writeln(-1); halt end;
    fillchar(d,sizeof(d),0);
    for i:=1 to n do inc(d[(c[i]-i+n)mod n]);
    for i:=0 to n-1 do if d[i]>m then m:=d[i];
    fillchar(d,sizeof(d),0);
    for i:=1 to n do inc(d[(c[i]+i-1)mod n]);
    for i:=0 to n-1 do if d[i]>m then m:=d[i];
    writeln(n-m);
    是么?

    0

    回复 lyrics发表于2008-10-12 19:55
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    技巧性比较强吧,楼下不必构造2次,计算时从头至尾算一次,再倒过来算一次就行了

    0

    回复 LV.唱响发表于2008-10-05 08:38
    置换群思想...今天刚明白...

    先构造新数列(要构造两次,否则只有70分),然后向右计算相对位置差,然后累加记录数组,然后用N减去相对位置差累加值最大的,就是答案...

    0

    回复 宇智波带波斯猫发表于2008-10-05 08:33
    Flag   Accepted
    题号   P1008
    类型(?)   其它
    通过   1065人
    提交   3000次
    通过率   35%
    难度   3

    第3000个提交的

    0

    回复 鸳鸯羡发表于2008-09-28 18:19
    #include <iostream>
    using namespace std ;

    int hash[50001];
    int n , i , j , t , maxs(0) ;

    inline void HASH ( int e[] )
    {
    for ( i = 1 ; i <= n ; i++ )
    {
    e[i] -= i ;
    if ( e[i] < 0 ) e[i] += n ;
    hash[e[i]]++ ;
    }
    for ( i = 0 ; i < 50001 ; i++ )
    if ( maxs < hash[i] ) maxs = hash[i] ;
    }

    int main(){
    cin >> n ;
    int e[n+1] , h[n+1][2] , e2[n+1];
    bool f[n+1] ;
    for ( i = 1 ; i <= n ; i++ )
    {
    f[i] = false ;
    cin >> h[i][0] >> h[i][1] ;
    }
    e[1] = 1 ;
    f[1] = true ;
    for ( i = 2 ; i <= n ; i++ )
    {
    if ( e < 0 ) { cout << -1 << endl ; exit(0) ; }
    if ( !f [ h[ e ][0] ] ) e[i] = h[ e ][0] ;
    if ( !f [ h[ e ][1] ] ) e[i] = h[ e ][1] ;
    f[ e[i] ] = true ;
    }
    for ( i = 1 , j = n ; i <= n ; i++,j-- ) e2[j] = e[i] ;
    HASH ( e ) ;
    memset ( hash , 0 , sizeof ( hash ) ) ;
    HASH ( e2 ) ;
    cout << n - maxs << endl ;
    }

    80分

    0

    回复 月光疾风发表于2008-09-25 13:03
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms
    纪念我第200次提交!过第79题。。。。

    0

    回复 ghostplant发表于2008-09-20 19:48
    #include <iostream>
    #include <fstream>
    #include <cassert>
    using namespace std;
    long N,seq[50001],p=1;
    class{
    private:
    long nbr[50001][3];
    bool flag[50001];
    bool isnbr(long v1,long v2){
    for(int i=1;i<=nbr[v1][0];i++)
    if(nbr[v1][i]==v2) return true;
    return false;
    }
    public:
    bool AddE(long v1,long v2){
    if(isnbr(v1,v2)) return true;
    else if(nbr[v1][0]==2||nbr[v2][0]==2) return false;
    else{
    nbr[v1][++nbr[v1][0]]=v2;
    nbr[v2][++nbr[v2][0]]=v1;
    return true;
    }
    }
    void dfs(long i){
    assert(!flag[i]);
    flag[i]=true,seq[p++]=i;
    for(int j=1;j<=nbr[i][0];j++){
    if(!flag[nbr[i][j]]){
    dfs(nbr[i][j]);
    break;
    }
    }
    }
    }G;
    long solve(void){
    long cnt1[50001]={0},cnt2[50001]={0},ans=0;
    for(int i=1,a,b;i<=N;i++){
    a=seq[i]-i;
    if(a<0) a+=N;
    b=seq[i]-(N+1-i);
    if(b<0) b+=N;
    if(++cnt1[a]>ans) ans=cnt1[a];
    if(++cnt2>ans) ans=cnt2;
    }
    return N-ans;
    }
    int main(){
    cin >> N;
    for(int i=1,nbr1,nbr2;i<=N;i++){
    cin >> nbr1 >> nbr2;
    if(!G.AddE(i,nbr1)||!G.AddE(i,nbr2)){
    cout << -1 << endl;
    return 0;
    }
    }
    G.dfs(1);
    cout << solve() << endl;
    return 0;
    }

    0

    回复 zzh19950802发表于2008-09-17 19:29
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案错误... ├ 标准行输出
     ├ 错误行输出
    ├ 测试数据 05:答案错误... ├ 标准行输出
     ├ 错误行输出
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 462ms
    ├ 测试数据 08:答案正确... 369ms
    ├ 测试数据 09:答案正确... 384ms
    ├ 测试数据 10:答案错误...程序输出比正确答案长
    为什么我的程序不对?
    #include <iostream>
    using namespace std;
    #define MAXN 50000
    int man[MAXN+2][2];
    int cercle[MAXN+2]={0,1};
    int used[MAXN+2]={0};
    int reduce[2][MAXN+2]={0};
    int n;
    int main()
    {
    long i,p,q=1,t;
    int max=0;
    cin>>n;
    for (i=1;i<=n;i++) cin>>man[i][0]>>man[i][1];
    p=man[q][1];
    for (i=2;i<=n+1;i++)
    {
    if (man[q][1]==p)
    {
    p=q;
    q=man[q][0];
    }
    else
    {
    if(man[q][0]!=p) break;
    p=q;
    q=man[q][1];
    }
    if(used[q]) break;
    else used[q]=1;
    cercle[i]=q;
    }
    if (i<=n+1) cout<<-1;
    else
    {
    for (i=1;i<=n;i++)
    {
    if((t=cercle[i]-i)<0) t+=n;
    reduce[0][t]++;
    if (reduce[0][t]>max) max=reduce[0][t];
    if ((t=cercle[i]-n+i-1)<0) t+=n;
    if (reduce[1][t]>max) max=reduce[1][t];
    }
    cout<<n-max;
    }
    return 0;
    }

    0

    回复 liaorc发表于2008-09-16 17:56
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 cxy450090074发表于2008-09-04 13:34
    oh no

    0

    回复 Lost.G发表于2008-08-22 15:49
    我在想``怎么样才能不看错这题呢

    0

    回复 bonism发表于2008-08-14 21:30
    时间复杂度O(N)。。。

    原来我一直把题意理解错。。。囧!!。。

    关于“置换群”,请看LRJ的《算法艺术与信息学竞赛》P245那一小节,还是比较好理解的。

    0

    回复 lemon_cn发表于2008-08-08 15:55
    热烈庆祝用pascal AC的第二题~
    p.s.我是C++的~~

    0

    回复 oipn4e2发表于2008-08-05 21:36
    解决效率不高,但AC了。

    0

    回复 notblack发表于2008-08-01 09:17
    用距离来分类,统计在原位的最大人数,奇怪的是
    b[1]:=1;
    b[2]:=a[1,1];
    b[n]:=a[1,2];

    建环的时候,上面的改成
    b[1]:=1;
    b[2]:=a[1,2];
    b[n]:=a[1,1];

    最后一个点却过不了,太奇怪了.

    0

    回复 332404521发表于2008-07-14 13:53
    对于初三刚刚中考完的我,要理解这题的意思是万万不能的。。。
    看题解我知道了应该怎么做,但那不是我的,所以不做了。。。
    哪天能证明出来那啥再来做

    0

    回复 Sheeta发表于2007-11-14 15:45
    好简单啊
    直接贪啊
    (P.S.置换群?什么东东...)

    0

    回复 mingyueyucai发表于2007-11-09 21:22
    我代码写了老长老长,结果还是只过了8个点,有没有搞错?
    我想请问一下,我和大家的一样,先排列出目标状态.然后确定初始状态时使得最多的人在目标位置上,然后交换.但是得到的答案总是偏大一点.
    然后我又把所有可以使最多的人在原位目标位置上的可能都尝试了一编(包括正反两个目标状态),结果还是只能过8个点,有2个点死都过不了!
    我的算法有什么问题吗?

    0

    回复 luanjiyang发表于2007-11-08 08:44
    很委琐的说 我提交了8遍。。
    0→0→10→10→10→10→70→AC

    • -||

    0

    回复 lonelycorn发表于2007-11-05 23:31
    数论……好底歇的东西。

    0

    回复 gamejifan发表于2007-11-04 11:15
    这题的叙述,让我误会了一年多。tzkq……3q..要早知道是这种意思早就ac了这题。。显然没什么大意思,看过组合数学或者学过群论的都懂。。ms跟polya计数法那个循环的意思。。

    写的时候竟然因为交换的时候写错一个字母wa。我汗。

    0

    回复 Alexandria发表于2007-11-01 13:33
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    好强大的题啊,不看题解还真不会!

    0

    回复 clfhaha1234发表于2007-10-30 18:09
    请问什么是置换群啊?可以讲讲吗?………………

    0

    回复 rleepas发表于2007-10-30 13:18
    楼下都是正解?
    ......

    0

    回复 Ice_Msk发表于2007-10-18 20:35
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    什么是置换群?不知道。。。照样过。。。。

    0

    回复 junlonely发表于2007-10-18 20:13
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    0

    回复 江南不才发表于2007-10-11 16:19
    排序法这里会超时~~~~~
    比赛的时间是2S~~
    这里是1S~~
    (_)

    0

    回复 秒杀群众发表于2007-10-10 17:05
    居然是置换群。。。
    对了。。。什么是置换群...
    上网查啊!!!

    0

    回复 southstarj1发表于2007-10-02 18:50
    思想:
    置换群。(相关知识自己查)
    对于一组数据,按各人的意愿排出一个序列,
    如果无法排出,就输出-1。
    再将环状序列变成链状,则这个目标序列为一个置换群,
    与原序列(按1到n的一列)满足:
    交换的最少人数等于目标序列与原序列不重合的人数。
    因为总共有2n个目标序列(正反各n种),都算一遍就行了。

    步骤:
    1. 读入数据;
    2. 构造一个目标序列;
    3. 统计该序列中元素位置与该元素在原序列位置的差值(同一方向)为i{i ∈ [0, n)}的元素个数;
    4. 将该序列的反序统计一遍;
    5. 从这些数据中选取一个最大的值max;
    6. 输出n - max;

    注意:
    构造目标序列时判断能否构造的条件;
    统计一次差值的复杂度是O(n);
    统计差值的目的是求与原序列最多的重合人数;

    0

    回复 wangjin5发表于2007-09-19 22:38
    好经典的题奥
    确实有难度

    0

    回复 the_melody发表于2007-09-03 17:58
    Accepted 有效得分:100 有效耗时:0ms
    好经典的题奥

    0

    回复 richardxx发表于2007-08-22 17:36
    下面程序是错的,不好意思,弄错地方了....

    0

    回复 sm-star发表于2007-08-21 15:18
    题目所求就是每次进行连续交换的人数总和,这样,一个看似复杂的题目就变的异常的简单了!

    0

    回复 wasyyyy发表于2007-08-11 02:05
    编译通过...
    ├ 测试数据 01:答案正确... 0ms
    ├ 测试数据 02:答案正确... 0ms
    ├ 测试数据 03:答案正确... 0ms
    ├ 测试数据 04:答案正确... 0ms
    ├ 测试数据 05:答案正确... 0ms
    ├ 测试数据 06:答案正确... 0ms
    ├ 测试数据 07:答案正确... 0ms
    ├ 测试数据 08:答案正确... 0ms
    ├ 测试数据 09:答案正确... 0ms

    ├ 测试数据 10:答案正确... 0ms

    Accepted 有效得分:100 有效耗时:0ms

    HOHO~~~看讨论的时候看到有人提到‘置换群’这个东西,突然想起来我刚买的一本组合数学上有这么一块东西,就拿过来看了。。。。
    然后就出现上面的东西了。。。。置换群,本来想求轮换的,发现轮换比较多,还是找不参与交换的比较好记。。。。

    优化的方法。。。我看了下好象不只一个人讲过了。。。而且似乎我跟他们的都一样(没仔细看)所以就不说了。。。效率是O(n)的。。不用建环。

    0

    回复 angieqiu发表于2007-08-10 22:49
    怎么判断建环失败啊?我的程序虽然AC但总觉得方法很傻

    0

    回复 梦ぁ逍遥发表于2007-07-17 13:45
    想到了用t[i]=b[i]-i表示环
    却没想到镜像..

    十分感谢visister
    让我从90分中挣扎出来...

    0

    回复 visister发表于2007-06-01 00:12
    首先明显地可以知道我们需要对于目标状态建立出一个环。如果无法建立这个环,那么结果一定是-1,当建立好环以后可以知道最小移动代价一定等于最少的不在目标位置上的人数。那么我们可以对目标环进行顺时针旋转1~n-1之中任意一个,答案就一定等于旋转中的不在自己位置上的人数最少的那样的环的状态。但是对于50000的数据,我们如果要将环旋转1~n-1次,那么总共加上判断不在自己位置上的人数时间复杂度为O(n^2),显然在限定时间内是无法出解的。因此我们进行逆向思维:不在自己位置上最少的人数就一定会等于总人数减去在自己位置上最多的人数(仔细想想),那么我们就将该问题转化为了求在自己的位置上最多的人数,这样一来,我们对初始目标环中每一个位置进行判断需要旋转多少次可以回到自己位置上,每一个人的选择都将映射到[0..n-1]的数组中,选取当中最大的情况就为所求,但是考虑到环可以反转,那么我们还需要将环再求一次镜像,就可以得到初始目标需要旋转多少次可以得到在自己位置上最多的人数的环的状态,最后通过总的人数减去它即为问题所求,时间复杂度为O(n);

    0

    回复 pyh119发表于2006-11-16 20:11
    哪个人不小心失火了找我啊!!!

    PS:我是安徽省芜湖市119接线员....

    0

    回复 maomingming发表于2006-11-06 18:40
    考虑旋转后最多可能重合的情况,另要注意圈可以反过来

    0

    回复 qian5发表于2006-09-30 21:35
    直接输出‘-1’有一个点过

    0

    回复 BambooLeaf发表于2006-09-26 18:17
    见过的最牛最简单的方法……
    将此题转换为冒泡排序,记录下所有交换的次数和两数间的距离,加上就行了……—__—|||
    具体是这样的,我们反向思维,本来是要求一个有序数列求出成为无序数列的代价,现在我们把无序数列(即目标数列)进行冒泡排序,然后……就是这样……
    看完之后,偶巨汗……

    0

    回复 xcjzj发表于2006-09-26 17:18
    每组数据确定两组相对位置关系,并且这两组互为镜像。
    对于某一种排列方式,不在需要位置上的人数即为当前状态到目标状态的最小代价。
    先找出其中一种排列方式。由于目标状态可以通过旋转而使得部分人的变化次数减少,所以找出每个人通过某一固定方向旋转到达目标位置的旋转次数。找到某一次数,使得拥有这个次数的人数最多。那么,通过旋转这一最多人拥有的次数,即可使得尽可能多的人不通过交换直接到达目标位置。于是,不拥有这一旋转次数的人数即为这一状态下的最小代价。
    然后,用现在的目标状态找出其镜像状态,并且用上述方法再找一遍最小代价,与前面的结果比较,较小值即为答案。
    另外,题目中会出现一些无解的情况:
    1.某个人被“要”的次数多于两次,也就是说有多于两个的人想要与他(她)邻座,那么无解。
    2.根据要求得出的目标状态为多于一个的环,也无解。

    0

    回复 东邪歪刀发表于2006-07-28 17:27
    提交了若干次……残念……

    0

    回复 sugar发表于2006-07-28 16:26
    这题比赛时真有人ac?
    真不好想
    为什么得开longint啊?

    0

    回复 晶星发表于2006-07-25 13:29
    排列本质不同的只有二种 正着和反着的
    检验几个人不在位置上用数学方法:)模拟法超时的

    0

    回复 tzkq发表于2006-07-23 04:37
    注意别误解题意 b1,b2....bm并不指连续位置上的数

    0

    回复 Coldwings发表于2006-01-26 09:21
    可以用群论证明:如果有k个人不在自己的位置上,那么要且仅要k的代价,即可使这些人归位

    剩下的..很简单了吧...

    0

    回复 lemon_cn发表于2008-08-08 15:55
    热烈庆祝用pascal AC的第二题~
    p.s.我是C++的~~

  • -1
    @ 2013-02-16 10:10:32
    • @ 2014-09-09 09:24:55

      怎么又是你??你有什么企图?骗访问量???垃圾!

信息

ID
1008
难度
5
分类
组合数学 点击显示
标签
递交数
4127
已通过
1375
通过率
33%
被复制
33
上传者