CF 936C Lock Puzzle——构造

题目:http://codeforces.com/contest/936/problem/C

  玩了一个小时,只能想出 5*n 的方法。

  经过一番观察?考虑这样构造:已经使得 A 串的一个后缀 = B 串的一个前缀,考虑再把一个正确的字符挪到 A 串的最后面。

  设该字符为 x 、它之前有 len 个字符、当前已经弄好的结尾长度为 l2 。

  进行这5个操作:n-len , len , n-len-l2 , l2 , n-l2+1 。

  思路就是:

  1&2:使得 x 变成结尾;

  3:使 x 变成开头、原来做好的部分变成结尾;

  4:原来做好的部分拼到 x 前面;

  5:新的做好的部分变成后缀。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2005,K=26;
int n,m,ct[K];
char a[N],b[N];
void Rv(int l,int r)
{
  for(int i=l,j=r;i<j;i++,j--)
    swap(a[i],a[j]);
}
void To_tail(int x)
{
  char w=a[x];
  for(int i=x;i<n;i++)a[i]=a[i+1];
  a[n]=w;
}
int main()
{
  scanf("%d%d",&n,&m);
  scanf("%s",a+1); scanf("%s",b+1);
  for(int i=1;i<=n;i++)
    ct[a[i]-‘a‘]++;
  for(int i=1;i<=n;i++)
    ct[b[i]-‘a‘]--;
  for(int i=0;i<K;i++)
    if(ct[i]!=0){puts("-1");return 0;}
  if(m<5*(n-1)+2){puts("-1");return 0;}
  printf("%d\n",5*(n-1)+2*(b[1]!=a[n]));//not +2!!!
  int len=0;
  if(b[1]!=a[n])
    {
      for(int i=1;i<=n;i++)
    if(a[i]==b[1]){len=i-1;break;}
      printf("%d %d ",n-len,len);
      Rv(1,len); Rv(len+1,n);
    }
  for(int l2=1,ps=2;l2<n;l2++,ps++)
    {
      for(int i=1;i<=n;i++)
    if(a[i]==b[ps]){len=i-1;break;}
      printf("%d %d %d %d %d ",n-len,len,
         n-len-l2,l2,n-l2-1);
      Rv(len+1,n-l2); To_tail(n-l2);
    }
  puts(""); return 0;
}

  刚才写着题解,忽然发现可以随随便便变成 3*n 的嘛!

  1.n-len-1,使得 x 变成结尾,并且原来做好的部分倒序变成开头;

  2.1,使 x 接在最前面;

  3.n,整体翻转,就变成正序的“原来做好的部分”后面添了一个 x 了!

  题解是 2.5*n 的。考虑做好的部分允许在过程中变成倒序的,然后一次5个操作往上添2个字符。

  设现在 A 串的后缀是 B 串的 [ L , R ] 部分。考虑扩充成 [ L-1 , R+1 ] 。设 y 是要往 A 的最后面放的、 x 是要往“已经做好的部分”的前面放的。

  1.把 x 露出来(放到结尾),此时原来做好的部分倒序在开头;

  2.翻转整个序列,现在原来部分正序在结尾, x 在开头;

    这一步很巧妙!这样可以让再做一步之后,原来部分的另一端露在开头;

  3.原来部分接在最前面;此时原来部分是倒序;

  4.找到 y 的位置,操作含 y 的对应后缀,这样 y 接在了“倒序的原来部分”的前面,并且整个部分在序列里面;

    这一步的思想很大胆!允许做好的部分埋在序列中部;

  5.操作后缀,使得做好的部分成为后缀;此时的做好部分是翻转过的状态,即原来按顺序对应的是 [ L , R ] 的话,现在是 [ R , L ] 。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2005,M=5005,K=26;
int n,m,ct[K],p[M],tot;
char a[N],b[N],c[N];
void cz(int x)
{
  for(int i=n-x+1,j=x;i<=n;i++,j--)
    c[j]=a[i];
  for(int j=x+1,i=1;j<=n;i++,j++)
    c[j]=a[i];
  memcpy(a,c,sizeof c); p[++tot]=x;
}
int main()
{
  scanf("%d%d",&n,&m);
  scanf("%s",a+1); scanf("%s",b+1);
  for(int i=1;i<=n;i++)
    ct[a[i]-‘a‘]++;
  for(int i=1;i<=n;i++)
    ct[b[i]-‘a‘]--;
  for(int i=0;i<K;i++)
    if(ct[i]!=0){puts("-1");return 0;}
  int l,r,x,y; l=r=(n+1)>>1;
  if(a[n]!=b[l])
    {
      for(int i=1;i<=n;i++)
    if(a[i]==b[l]){x=i;break;}
      cz(n-x);
    }
  bool fx=0;
  for(l--,r++;l>=1;l--,r++)
    {
      for(int i=1;i<=n;i++)
    if(a[i]==b[l]){x=i;break;}
      for(int i=1;i<=n;i++)
    if(a[i]==b[r]&&i!=x){y=i;break;}
      if(fx)swap(x,y); fx=!fx; char tp=a[y];
      cz(n-x); cz(n); cz(r-l-1);
      for(int i=r-l+1;i<=n;i++)
    if(a[i]==tp){y=i;break;}
      int tmp=n-y; cz(n-y+1); cz(n-tmp-(r-l+1));
    }
  if((n&1)==0&&!fx){ cz(n-1); cz(1); fx=!fx;}
  if(fx)cz(n);
  printf("%d\n",tot);
  for(int i=1;i<=tot;i++)printf("%d ",p[i]);puts("");
  return 0;
}

原文地址:https://www.cnblogs.com/Narh/p/10878173.html

时间: 2024-08-05 02:04:14

CF 936C Lock Puzzle——构造的相关文章

HDU 4708 Rotation Lock Puzzle (贪心+模拟)

Rotation Lock Puzzle Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1668    Accepted Submission(s): 530 Problem Description Alice was felling into a cave. She found a strange door with a number

hduoj 4708 Rotation Lock Puzzle 2013 ACM/ICPC Asia Regional Online —— Warmup

http://acm.hdu.edu.cn/showproblem.php?pid=4708 Rotation Lock Puzzle Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Description Alice was felling into a cave. She found a strange door with a number square m

Codeforces Round #467 (Div. 2) E -Lock Puzzle

Lock Puzzle 题目大意:给你两个字符串一个s,一个t,长度<=2000,要求你进行小于等于6100次的shift操作,将s变成t, shift(x)表示将字符串的最后x个字符翻转后放到最前面. 思路:不会写,看了题解... 因为长度为3000,操作为6500,我们考虑每三次操作将一个字符放到最后,并保证其他字符的顺序不变,这样是可以实现的, 如果我们想要将第k个字符移到最后,我们只要shift(n-1-k) , shift(1) , shift(n-1),就能实现啦 . 1 #incl

HDU 4708 Rotation Lock Puzzle(数学啊)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4708 Problem Description Alice was felling into a cave. She found a strange door with a number square matrix. These numbers can be rotated around the center clockwise or counterclockwise. A fairy came an

CF936C Lock Puzzle

题目链接:戳我 APIO2019 practice round E题的弱化版 考虑如何构造. 对于一个字符串a: (未构造好的)+a[pos]+(已构造好的) 1.将已经构造好的按照题目意思翻转,接到前面 (反着的已构造好的)+(未构造好的)+a[pos] 2.将a[pos]按照题目意思翻转(但是因为它就一个数,所以还是不变),接到前面 a[pos]+(反着的已构造好的)+(未构造好的) 3.翻转长度为n,接到前面(因为是所有的了,所以接到前面这一步相当于没有,该操作等效于整体翻转) (未构造好

HDU4708 Rotation Lock Puzzle 不错的模拟题

题意:给你一个n*n的矩阵,n为奇数,以最中心的一个数为基准,可以把这个矩阵 看成一圈一圈的,每一圈都可以逆时针或者顺时针旋转,每一次旋转每个元素只能移动一个单元格,求经过每一圈的旋转矩阵两个对角线和最大的值,并求出最少旋转次数 一圈一圈的处理,注意最中心的那个数不用管,就它一个,那么这个矩阵只有n/2圈需要操作,对于每一圈的元素都放在一个一维数组里面,然后枚举这个数组里的每一个元素为开头,统计接下来的三个数,求和比较大小即可,因为有逆时针的,所以顺时针时从开头开始枚举,逆时针则从尾部开始枚举,

HDU 4708 Rotation Lock Puzzle

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4708 测试数据: 51 9 9 1 11 9 9 9 99 9 9 9 99 9 9 9 11 1 9 9 1 81 1 1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 using namespace std; 5 long long a[15][15]; 6 long long step,an

CF.911F.Tree Destruction(构造 贪心)

题目链接 \(Description\) 一棵n个点的树,每次可以选择树上两个叶子节点并删去一个,得到的价值为两点间的距离 删n-1次,问如何能使最后得到的价值最大,并输出方案 \(Solution\) 树上距离,求最大,可以考虑下树的直径 假如已知树的直径u->v,那么任意一点x到达其他点的最远距离就是u,v中一点(如果不是这样,那直径一定可以更长而不是uv) 假设x距u最远,那肯定是删x 删直径上的点(直径端点)会导致一些点取不到最远距离 既然这样按顺序删非直径上的点,最后删直径端点 #in

Codeforces 627F Island Puzzle - 构造

题目传送门 传送门I 传送门II 传送门III 题目大意 (八数码问题的树上版本). 已经存在解的时候直接输出最少的移动步数. 否则允许加入一条边,要求输出边的端点以及最少的移动步数. 仍然无解输出-1. 不添加边的时候方案是唯一的:直接把0移动到目的地,然后判断是否有解. 考虑把$0$移动到目的后,把0当做根.因为操作可逆,这个时候是否存在解与原图是否存在解等价. 考虑此时0走到一个环上转移圈的意义:把进入点先拿出来,转上若干圈,回到起点,把原来的进入点放回环中. 所以所有不合法的位置只有两种