zoukankan      html  css  js  c++  java
  • 【GMOJ5102】小学生语文题

    题目

    题目链接:https://gmoj.net/senior/#main/show/5102

    (Qleq 10,nleq 2000)

    思路

    下文把第一个串称作 (s) 串,第二个串称作 (t) 串。
    假设我们从后往前考虑,如果要把位置 (i) 往前移到 (j),可以看做枚举到位置 (i) 的时候把位置 (i) 的字符拎出来,枚举到 (j) 的时候再放下去。
    (f[i][j]) 表示 (t) 串第 (jsim n) 位中,拎出了 (i-j) 个字符没有放回去,剩余 (n-i) 个字符依次排到最后与 (s)(isim n) 恰好匹配时,最小的操作次数。
    那么 (f[i][j]) 有三种转移方式:

    • (f[i][j]=f[i+1][j]):当 (t[jsim n]) 中字符 (s[i]) 的出现次数严格大于 (s[i+1sim n]) 中字符 (s[i]) 的出现次数。
    • (f[i][j]=f[i+1][j+1]):当 (s[i]=t[i]) 时,这两位可以直接匹配上。
    • (f[i][j]=f[i][j+1]+1):把 (t[j]) 拎出来。

    最后答案就是 (f[1][1])
    至于输出方案,我们发现只有进行第二种转移时才不需要多移动,否则直接往后暴力找到一个相同的字符暴力移动一下即可。
    时间复杂度 (O(Qn^2))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=2010;
    int Q,n,f[N][N],pre[N][N][2],cnt[2][N][26];
    char s[N],t[N];
    bool flag[2][N];
    
    int main()
    {
    	freopen("chinese.in","r",stdin);
    	freopen("chinese.out","w",stdout);
    	scanf("%d",&Q);
    	while (Q--)
    	{
    		memset(f,0x3f3f3f3f,sizeof(f));
    		memset(flag,0,sizeof(flag));
    		memset(cnt,0,sizeof(cnt));
    		scanf("%s%s",s+1,t+1);
    		n=strlen(s+1);
    		for (int i=n;i>=1;i--)
    			for (int j=0;j<26;j++)
    			{
    				cnt[0][i][j]=cnt[0][i+1][j]+(s[i]-'a'==j);
    				cnt[1][i][j]=cnt[1][i+1][j]+(t[i]-'a'==j);
    			}
    		for (int i=1;i<=n+1;i++) f[n+1][i]=n-i+1;
    		for (int i=n;i>=1;i--)
    			for (int j=i;j>=1;j--)
    			{
    				if (cnt[1][j][s[i]-'a']>cnt[0][i+1][s[i]-'a'] && f[i][j]>f[i+1][j])
    					f[i][j]=f[i+1][j],pre[i][j][0]=i+1,pre[i][j][1]=j;
    				if (s[i]==t[j] && f[i][j]>f[i+1][j+1])
    					f[i][j]=f[i+1][j+1],pre[i][j][0]=i+1,pre[i][j][1]=j+1;
    				if (f[i][j]>f[i][j+1]+1)
    					f[i][j]=f[i][j+1]+1,pre[i][j][0]=i,pre[i][j][1]=j+1;
    			}
    		for (int i=1,j=1;i<=n;)
    		{
    			if (pre[i][j][0]==i+1 && pre[i][j][1]==j+1)
    				flag[0][i]=flag[1][j]=1;
    			int x=i,y=j; i=pre[x][y][0]; j=pre[x][y][1];
    		}
    		cout<<f[1][1]<<"
    ";
    		for (int i=1;i<=n;i++)
    			if (!flag[0][i])
    				for (int j=i+1;j<=n;j++)
    					if (!flag[1][j] && s[i]==t[j])
    					{
    						cout<<j<<" "<<i<<"
    ";
    						flag[1][j]=1;
    						for (int k=j;k>i;k--)
    						{
    							swap(flag[1][k],flag[1][k-1]);
    							swap(t[k],t[k-1]);
    						}
    						break;
    					}
    	}
    	return 0;
    }
    
  • 相关阅读:
    BZOJ 1051: [HAOI2006]受欢迎的牛( tarjan )
    BZOJ 2208: [Jsoi2010]连通数( DFS )
    js效果-鼠标提示框
    CSS-背景
    CSS-文本
    tomcat 安装 for Mac
    CSS选择器基础
    POJ3349-Snowflake Snow Snowflakes-Hash
    数据库的三大设计范式
    HDU5120-Intersection-两个圆环相交面积
  • 原文地址:https://www.cnblogs.com/stoorz/p/15021677.html
Copyright © 2011-2022 走看看