DP(区间专题Ⅶ)

20 篇文章 0 订阅
14 篇文章 0 订阅

题意: 某人有一套玩具,并想法给玩具命名。首先他选择WING四个字母中的任意一个字母作为玩具的基本名字。然后他会根据自己的喜好,将名字中任意一个字母用“WING”中任意两个字母代替,使得自己的名字能够扩充得很长。现在,他想请你猜猜某一个很长的名字,最初可能是由哪几个字母变形过来的。

>> face <<

Strategy:区间dp, 先将字符离散成数字[1~4], 然后区间dp, 针对每个区间, 可以枚举区间断点, 把其分成两个小区间(套路), 然后判断两个小区间是否能被压缩出出来, 感觉区间dp可以写, 记忆搜索也行, 这里给出递推的版本

状态: d p [ l ] [ r ] [ k ] → dp[l][r][k]\to dp[l][r][k]区间[l, r]是否能被压缩成k

目标: d p m i n [ 1 ] [ n ] [ i ∈ [ 1 , 4 ] ] dpmin[1][n][i\in [1, 4]] dpmin[1][n][i[1,4]]

边界: d p [ i ] [ i ] [ t o i n t ( a [ i − 1 ] ) ] = 1 dp[i][i][toint(a[i-1])]=1 dp[i][i][toint(a[i1])]=1区间[i,i]能由字符i压缩来

合法判断: 条件转移, 满足左右区间能同时转移才行

转移方程: 见下

attention: 注意边界

双倍经验:

  • 数据的存储
  • 状态的设计
#include <bits/stdc++.h>
#include <bits/extc++.h>
#define _rep(i, a, b) for (ll i = (a); i <= (b); ++i)
#define _rev(i, a, b) for (ll i = (a); i >= (b); --i)
#define _for(i, a, b) for (ll i = (a); i < (b); ++i)
#define _rof(i, a, b) for (ll i = (a); i > (b); --i)
#define ll long long
#define db double
#define oo 0x3f3f3f3f
#define eps 0.00001
#define all(x) x.begin(), x.end()
#define met(a, b) memset(a, b, sizeof(a))
#define id(x) ((x + 8))
#define bin(x) cerr << #x << " is " << bitset<15>(x) << endl
#define what_is(x) cerr << #x << " is " << x << endl
#define lowbit(x) x &(-x)
using namespace std;
const int maxn = 210;
int num[5], change[66][3], cnt, n;
string a; 
bool dp[maxn][maxn][5];
inline int to_int(char o){
	if(o == 'W')return 1;
	if(o == 'I')return 2;
	if(o == 'N')return 3;
	if(o == 'G')return 4;
}
int main(){
	ios::sync_with_stdio(0);
	_rep(i, 1, 4){
		cin >> num[i];
	}
	_rep(i, 1, 4){
		_rep(j, 1, num[i]){
			string aa;
			cin >> aa;
			change[++cnt][0] = i;
			change[cnt][1] = to_int(aa[0]);
			change[cnt][2] = to_int(aa[1]);
		}
	}
	cin >> a;
	n = a.size();
	_rep(i, 1, n)dp[i][i][to_int(a[i-1])] = 1;
	_rep(len, 2, n){
		_rep(l, 1, n - len + 1){
			int r = l + len - 1;
			_rep(k, l, r){
				_rep(i, 1, cnt){
					if(dp[l][k][change[i][1]] && dp[k+1][r][change[i][2]]){
						dp[l][r][change[i][0]] = 1;
					}
				}
			}
		}
	}
	bool out = 0;
	_rep(i, 1, 4){
		if(dp[1][n][i]){
			out = 1;
			if(i == 1)putchar('W');
			if(i == 2)putchar('I');
			if(i == 3)putchar('N');
			if(i == 4)putchar('G');
		}
	}
	if(! out){
		cout << "The name is wrong!" << endl;	
	}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值