码迷,mamicode.com
首页 > 其他好文 > 详细

Luogu3516 POI2011 Shift 构造

时间:2018-10-21 14:17:31      阅读:210      评论:0      收藏:0      [点我收藏+]

标签:写作   传送门   def   front   没有   有一个   ret   stl   ack   

传送门

题意:给出一个长为$N$的排列,有两种操作:$A$:将最后一个数字放到第一个;$B$:将第三个数字放到第一个。一次性使用某种操作$k$次写作$kA$或$kB$,其中在$kA$中$k < N$,在$kB$中$k < 3$。请给出一种方案使得序列变为$1,2,3...N$。$N \leq 2000$


 

一道比较难的构造题

我们考虑增量构造:假如我们已经将$1-i$排好了,如何将$i+1$排到它们后面。我们可以进行如下操作:

$1.$通过若干$A$操作将$i+1$放到序列开头的位置

$2.$重复$2A,1B$操作将$i$与$i+1$之间不必要的数字两两踢到$i+1$后面

$3.$如果序列最后还有一个多余的数字,使用$1A,2B$操作将它踢到$i+1$后面

这样$i$与$i+1$就能相连了。

但是当我们需要将$n-1$接上时,会有一些问题:

我们考虑这样的一个序列:$$n-1,1,2,3...n-2,n$$

如果我们使用$1A,2B$操作,$n$就会夹在$1$和$2$中间,打乱了我们之前排好的顺序。所以当我们需要排$n-1$和$n$时,这种方法是不可行的。不妨考虑另外一种构造方法。

我们将$n$移到第一个,也就是$$n,n-1,1,2,3...n-2$$

然后我们使用一次$2A,1B$操作,然后序列就变成了……

$$n,n-3,n-2,n-1,1,2,3...n-4$$

发现$n$的位置没有变,但是后面$n-1$个数在循环。那么我们不断重复该操作,直到序列变成$$n,1,2,3...n-2,n-1$$就行了。但实际上在当前情况下当$n$为奇数的时候是不可行的,因为在移动若干次之后,序列会变成$$n,2,3,4...n-1,1$$,再一次重复该操作又会把$n-1$踢到前面去了。

可以发现所有操作都是$O(n)$级别的,总操作次数是$O(n^2)$级别的,与题设刚好一致

稍微注意一下输出

关于序列移动的模拟操作建议使用链表。如果比较懒,可以使用STL中的deque,开O2的情况下效率还是比较优秀的(不开O2是最慢的)

下面的代码:O2 497ms,无O2 2146ms

  1 #include<bits/stdc++.h>
  2 #define MAXN 5000010
  3 using namespace std;
  4 
  5 inline int read(){
  6     int a = 0;
  7     char c = getchar();
  8     while(!isdigit(c))
  9         c = getchar();
 10     while(isdigit(c)){
 11         a = (a << 3) + (a << 1) + (c ^ 0);
 12         c = getchar();
 13     }
 14     return a;
 15 }
 16 
 17 char done[MAXN] , allDone[MAXN];
 18 int step[MAXN] , allStep[MAXN] , pot[MAXN] , N , cnt;
 19 deque < int > now;
 20 
 21 inline void moveA(int s){
 22     if(done[cnt] != a)
 23         done[++cnt] = a;
 24     step[cnt] += s;
 25     for(int i = 1 ; i <= s ; i++){
 26         now.push_front(now.back());
 27         now.pop_back();
 28     }
 29 }
 30     
 31 inline void moveB(int s){
 32     if(done[cnt] != b)
 33         done[++cnt] = b;
 34     step[cnt] += s;
 35     for(int i = 1 ; i <= s ; i++){
 36         int p = now[2];
 37         now[2] = now[1];
 38         now[1] = now[0];
 39         now[0] = p;
 40     }
 41 }
 42 
 43 inline void output(){
 44     int calc = 0;
 45     for(int i = 1 ; i <= cnt ; i++)
 46         if(done[i] != allDone[i]){
 47             if(step[i] %= (done[i] == a ? N : 3)){
 48                 allDone[++calc] = done[i];
 49                 allStep[calc] = step[i];
 50             }
 51         }
 52         else
 53             if((allStep[i] + step[i]) % (done[i] == a ? N : 3))
 54                 allStep[i] = (allStep[i] + step[i]) % (done[i] == a ? N : 3);
 55             else
 56                 allDone[calc--] = 0;
 57     cout << calc << endl;
 58     for(int i = 1 ; i <= calc ; i++)
 59         cout << allStep[i] << allDone[i] <<  ;
 60 }
 61 
 62 int main(){
 63     N = read();
 64     for(int i = 1 ; i <= N ; i++)
 65         now.push_back(read());
 66     if(N == 1){
 67         putchar(0);
 68         return 0;
 69     }
 70     else
 71         if(N == 2){
 72             cout << (now[0] == 1 ? "0" : "1\n1a");
 73             return 0;
 74         }
 75     for(int i = 2 ; i < N - 1 ; i++){
 76         for(int j = 0 ; j < N ; j++)
 77             if(now[j] == i){
 78                 if(j)
 79                     moveA(N - j);
 80                 break;
 81             }
 82         while(now[N - 1] != i - 1)
 83             if(now[N - 2] != i - 1){
 84                 moveA(2);
 85                 moveB(1);
 86             }
 87             else{
 88                 moveA(1);
 89                 moveB(2);
 90             }
 91     }
 92     for(int i = 0 ; i < N ; i++)
 93         if(now[i] == N){
 94             if(i)
 95                 moveA(N - i);
 96             break;
 97         }
 98     if(now[1] == N - 1){
 99         if(N & 1){
100             puts("NIE");
101             return 0;
102         }
103         while(now[N - 1] != N - 1){
104             moveA(2);
105             moveB(1);
106         }
107     }
108     moveA(N - 1);
109     output();
110     return 0;
111 }

 

Luogu3516 POI2011 Shift 构造

标签:写作   传送门   def   front   没有   有一个   ret   stl   ack   

原文地址:https://www.cnblogs.com/Itst/p/9824717.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!