zoukankan      html  css  js  c++  java
  • 【FJOI2015】金币换位问题

    Description

      桌子上有2N+2个位置,其中前N个位置放着N个正面朝上的硬币,接下来N个位置放着反面朝上的硬币,后面两个位置为空。

      每次操作可以将任意两个相邻的硬币顺序不变地移动到空位上,那么至少要多少次操作可以将硬币移成正反相间(正面的硬币在第一个,最后两个还是空)。

      例如:当N = 4时,有一组合法解如下:

        11110000__

        __11000011

        101__00011

        1010100__1

        10101__001

        10101010__

    Input Format

      输入一个n

    Output Format

      第一行输出最少移动步数

      接下来一行为移动方案,只要输出被移动的两个非空格格子左边那个的编号。换不换行无所谓。详见样例。

    Sample Input

    4

    Sample Output

    5
    1 4 8 6 9

    Hint

    对于100%的数据,2<n<=200000

    分析:

    首先需要先找到最少步数与N的关系,在考场上找到的是当N为偶数时,最少步数FN) = N * 2 - 3,当N为奇数时,FN) = N * 2 - 2,然后发现构造过程也很容易,随便搞搞就可以了。

    后来成绩出来,发现这一题没分。而且,全场都没有人有拿到分。。。很多人想到是N + 1,但是没有人构造出过程。

    回来之后,写了个暴力,只跑到N = 8的情况(再大内存受不了),发现答案确实是N + 1

    一个学长说这很像ACM WORLD FINAL 2014的第一题,就去研究了一下,但是按那道题的方法最终的结果是0101……也没有想到怎么将它转换为1010……

    后来CJK花了一整天的时间研究出一些思路,大致是分解成子问题,每次规模减小,后来又一步步完善,之后变成这样:

    对于一个类似11111111000000__00的子问题,可以转换为10101010__10101010__可以在任意01之间,但是不能是1__0),步骤如下:

    11111111000000__00

    1__111110000001100

    1001(111100__00)1100 (括号内表示下一个子问题)

    子问题解决之后,再经过下面的转换:

    1001(1010__1010)1100

    1001(1010101010)1__0

    10__(1010101010)1010

    这样就将当前的子问题解决了且子问题规模每次缩小4,而每次增加的步数也是4,那么就可以符合我们的要求。

    由于N > 2,所以我们的问题要从3开始处理(而且1本身就是结果,2无法解决),3456无法再分解为子问题,所以要内置3456的解法和对应子问题的解法。

    然后我又在暴力的基础上加了输出所有解,找出了3456的可行方案,分别是:

    32 6 4 7

    41 4 8 6 9

    52 7 11 3 8 11

    61 6 12 9 3 10 13

    然后子问题的解决方案:

    36 2 5

    48 1 4 7

    58 3 11 2 7

    610 2 12 9 6 3

    3来举个例子,当规模为3的子问题出现的时候,应该是这样:

    1__1(11100000)1100

    然后第一步将第67个位置上的0移开,变成1001(11100__0)1100

    接下来依次操作:

    1001(1__00110)1100

    1001(1010__10)1100

    然后就可以解决外面的子问题了。

    现在需要确定操作的规律,我们定义当前子问题的规模为N,起点为L,上一步操作为M,任意举一个例子N = 11的情况:

    1111111111100000000000__

    11111111111000000000__00        N = 11   L = 0   M = 21 = L + N * 2 - 1

    1__111111110000000001100        N = 11   L = 0   M = 2 = L + 2

    1001(111111100000__00)1100        N = 7   L = 4   M = 17 = L + N * 2 - 1

    1001(1__1111000001100)1100        N = 7   L = 4   M = 6 = L + 2

    1001(1001(11100__0)1100)1100        N = 3   L = 8   M = 14 = L + 6

    1001(1001(1__00110)1100)1100        N = 3   L = 8   M = 10 = L + 2

    1001(1001(1010__10)1100)1100        N = 3   L = 8   M = 13 = L + 5

    1001(1001101010101__0)1100        N = 7   L = 4   M = 18 = L + N * 2

    1001(10__101010101010)1100        N = 7   L = 4   M = 7 = L + 3

    100110101010101010101__0        N = 11   L = 0   M = 22 = L + N * 2

    10__10101010101010101010        N = 11   L = 0   M = 3 = L + 3

    1010101010101010101010__        N = 11   L = 0   M = 23 = L + N * 2 + 1

    从上面的过程中,我们可以发现一些规律,每次缩小规模时,解决子问题之前的操作都是L + N * 2 - 1 和 L + 2,而解决子问题之后的操作都是L + N * 2L + 3,中间规模为36的子问题特殊解决,然后大问题的最后一部都是将末尾两个移到前面,因为解决规模为36的子问题需要的步骤分别是36,加上最后一步,需要的操作数刚好是N + 1

     

    代码:

     

     1 #include <cstdio>
     2 int n, l;
     3 int main ()
     4 {
     5     scanf ("%d", &n);
     6     printf ("%d
    ", n + 1);
     7     if (n < 7)
     8     {
     9         switch (n)
    10         {
    11         case 3:    printf ("2 6 4 7 "); break;
    12         case 4:    printf ("1 4 8 6 9 "); break;
    13         case 5:    printf ("2 7 11 3 8 11 "); break;
    14         case 6:    printf ("1 6 12 9 3 10 13 "); break;
    15         }
    16         return 0;
    17     }
    18     for (l = 0; n >= 7; n -= 4, l += 4)
    19         printf ("%d %d ", l + (n << 1) - 1, l + 2);
    20     switch (n)
    21     {
    22     case 3:    printf ("%d %d %d ", l + 6, l + 2, l + 5); break;
    23     case 4:    printf ("%d %d %d %d ", l + 8, l + 1, l + 4, l + 7); break;
    24     case 5:    printf ("%d %d %d %d %d ", l + 8, l + 3, l + 11, l + 2, l + 7);break;
    25     case 6:    printf ("%d %d %d %d %d %d ", l + 10, l + 2, l + 12, l + 9, l + 6, l + 3); break;
    26     }
    27     for (l -= 4, n += 4; l >= 0; l -= 4, n += 4)
    28         printf ("%d %d ", l + (n << 1), l + 3);
    29     n -= 4;
    30     printf ("%d ", (n << 1) + 1);
    31 }

     

     

     

  • 相关阅读:
    梯度下降-Momentum
    6-10-HIRP OPEN 2016
    机器学习数目推荐
    《统计、计算和未来-李航》读后感
    MongoDB $关键字 $修改器
    MongoDB数据类型
    MongoDB操作(增删改查)
    MongoDB安装及开启(Windows)
    第七周:论文泛读(二)
    第六周:论文泛读(一)
  • 原文地址:https://www.cnblogs.com/lightning34/p/4384537.html
Copyright © 2011-2022 走看看