【GDOI2017】小学生语文题

【GDOI2017】小学生语文题

by AmanoKumiko

Description

已知串T,S,所有字母在两个串中出现次数相同,每次可以把S中后面的字符调至前面任意位置,求把S变成T的最少移动次数

Input

第一行一个整数N,表示N组数据

接下来每组数据两个串T和S

Output

每组数据第一行为最少移动次数

接下来为方案(spj)

Sample Input

3
abc
abc
sysu
ssyu
aaab
baaa

Sample Output

0
1
3 2
3
2 1
3 1
4 1

Data Constraint

\(len<=2000,N<=10\)

Solution

我一看这不是签到题吗?然后信仰贪心,发现是假的。。。

好吧省选Day2T3不是唬人///

正解:

类似于LCS的DP

\(f[i][j]\)表示\(T\)串匹配了\(i-len\)\(S\)串取出了\(j-len\)的字符的最少移动次数

显然有三种转移

\(f[i+1][j]->f[i][j]\) 即已经取出的字符\(T[i]\)的个数足够匹配,前缀/后缀和判一下

\(f[i][j+1]+1->f[i][j]\) 即取出字符,但不一定立即匹配

\(f[i+1][j+1]->f[i][j]\) 即当前位相同,不需取字符

然而最恶心的是构造方案。。。

记录一个\(pre[i][j]\)表示属于哪种转移

如果是第二种则说明这个是被调动的字符,打个标记

然后枚举\(T\)的每个位置,若不同,则找出\(S\)中最近(自己想为什么不是最远的)的有标记的且字符相同的位置,暴力调动

Code

#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define N 2010

char s[N],t[N];
int n,len,f[N][N],st[N][26],ss[N][26],num[N],nt,tag[N];
struct node{int a,b;}pre[N][N];

int main(){
	freopen("chinese.in","r",stdin);
	freopen("chinese.out","w",stdout);
	scanf("%d",&n);
	while(n--){
		scanf("%s",t+1);
		len=strlen(t+1);
		scanf("%s",s+1);
		F(i,1,len){
			F(j,0,25)ss[i][j]=ss[i-1][j],st[i][j]=st[i-1][j];
			st[i][t[i]-'a']++;ss[i][s[i]-'a']++;
		}
		memset(f,127,sizeof(f));
		F(i,1,len+1)f[len+1][i]=len-i+1;
		Fd(i,len,1) Fd(j,i,1){
			if(st[len][t[i]-'a']-st[i-1][t[i]-'a']<=ss[len][t[i]-'a']-ss[j-1][t[i]-'a']){
				if(f[i+1][j]<f[i][j])f[i][j]=f[i+1][j],pre[i][j]=(node){i+1,j};
			}
			if(t[i]==s[j]){
				if(f[i+1][j+1]<f[i][j])f[i][j]=f[i+1][j+1],pre[i][j]=(node){i+1,j+1};
			}
			if(f[i][j+1]+1<f[i][j]){
				f[i][j]=f[i][j+1]+1;pre[i][j]=(node){i,j+1};
			}
		}
		printf("%d\n",f[1][1]);
		node now=(node){1,1};nt=0;
		memset(tag,0,sizeof(tag));
		while(now.a<=len&&now.b<=len){
			node last=pre[now.a][now.b];
			if(last.a==now.a&&last.b==now.b+1)tag[now.b]=1;
			else if(last.a==len+1){Fd(i,len,last.b)tag[i]=1;}
			now=last;
		}
		F(i,1,len)if(t[i]!=s[i]){
			int pos=0;
			F(j,i+1,len)if(tag[j]&&s[j]==t[i]){pos=j;break;}
			Fd(j,pos,i+1)swap(s[j],s[j-1]),swap(tag[j],tag[j-1]);
			printf("%d %d\n",pos,i);
		}
	}
	return 0;
}
posted @ 2021-07-16 22:13  冰雾  阅读(78)  评论(0编辑  收藏  举报