2016 Multi-University Training Contest 2 1012 La Vie en rose

題目鏈接:點擊打開鏈接

題目大意:給你兩個字符串a、b,b串中每個字母都可以和相鄰的字母交換但只能交換一次,問a串中有多少位置可以和b串匹配。

解題思路:比賽的時候隊友是暴力過的,後來看了官方題解打算試一下dp,對於dp[i][j][k](k=0,1,2)表示a字符串匹配到第i位,b字符串匹配到第j位,k=0表示這一位和前一位交換,k=1表示這一位不做任何處理,k=2表示這一位和後一位交換,那麼就有一下狀態轉移方程:

dp[i][j][0]=dp[i-1][j-1][2]&&(a[i]==b[j-1]);

dp[i][j][1]=(dp[i-1][j-1][0]||dp[i-1][j-1][1])&&(a[i]==b[j])

dp[i][j][2]=(dp[i-1][j-1][0]||dp[i-1][j-1][1])&&(a[i]==b[j+1])

代碼:

#include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
#include<ctime>
#include "cstdio"
#include "string"
#include "string.h"
#include "map"
using namespace std;
int dp[5000][3];
char str1[100001], str2[5001];
int ans[1000001];
int main()
{
	int T, m, n;
	scanf("%d", &T);
	while (T--)
	{
		memset(ans, 0, sizeof(ans));
		memset(dp, 0, sizeof(dp));
		scanf("%d %d %s %s", &n, &m, str1, str2);
		if (m == 1)
		{
			for (int i = 0;i < n;i++)
			{
				if (str1[i] == str2[0])
					printf("1");
				else
					printf("0");
			}
			puts("");
			continue;
		}
		for (int i = 0;i < n;i++)
		{
			int now = i+1;
			dp[0][1] = (str1[i] == str2[0]);
			dp[0][2] = (str1[i] == str2[1]);
			//cout << dp[0][1] << " " << dp[0][2] << endl;
			if (!(dp[0][1] || dp[0][2]))
				continue;
			bool flag = true;
			for (int j = 1;j < m;j++)
			{
				if (now == n)
				{
					flag = false;
					break;
				}
				dp[j][0] = dp[j - 1][2] && (str1[now] == str2[j - 1]);
				dp[j][1] = (dp[j - 1][0] || dp[j - 1][1]) && (str1[now] == str2[j]);
				if (j != m - 1)
					dp[j][2] = (dp[j - 1][0] || dp[j - 1][1]) && (str1[now] == str2[j + 1]);
				if (dp[j][0] || dp[j][1] || dp[j][2])
					now++;
				else
				{
					flag = false;
					break;
				}
			}
			if (flag)
				ans[i] = 1;
		}
		for (int i = 0;i < n;i++)
			printf("%d", ans[i]);
		puts("");
	}
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章