Codeforces 544E Remembering Strings 状压dp

题目链接

题意:

给定n个长度均为m的字符串

下面n行给出字符串

下面n*m的矩阵表示把对应的字母修改成其他字母的花费。

问:

对于一个字符串,若它是easy to remembering 当 它存在一个字母,使得这个字母在这一列是独一无二的。

要使得n个字符串都是easy to remembering 的最小花费。

第一个样例是把第一列的4个a中3个a修改成别的字母,所以花费为3.

思路:

显然是个状压dp,但需要一点转化。

首先得到一个结论:

对于某一列,设这一列的字母是 a,a,b,b,a,d,c···

任意修改某种字母,都能使得包括该种字母的字符串变成unique

instance: 把所有的a字母都修改为别的字母,一定能使得修改后的字母与同列的其他字母不重复。

因为最多只有20个字符串,也就是修改后的字母种类至多只有20种。

然后状压已经easy to remembering的字符串的最小花费。

dp[i] 表示已经easy to remembering 的字符串状态为i时的最小花费。

两个转移:

1、直接修改字母

2、把这一列中所有与这个字母相同的字母都修改成别的字母。

当然可以剩下一个,剩下花费最大的那个即可。

cost[i][j] 就表示除了花费最大的那个 同列中与str[i][j]字母相同的花费和。

bit[i][j] 表示哪些字符串 在第j列 与 a[i][j] 字母相同。

#include <iostream>
#include <string>
#include <vector>
#include <cstring>
#include <cstdio>
#include <map>
#include <queue>
#include <algorithm>
#include <stack>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
using namespace std;
template <class T>
inline bool rd(T &ret) {
	char c; int sgn;
	if (c = getchar(), c == EOF) return 0;
	while (c != '-' && (c<'0' || c>'9')) c = getchar();
	sgn = (c == '-') ? -1 : 1;
	ret = (c == '-') ? 0 : (c - '0');
	while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
	ret *= sgn;
	return 1;
}
template <class T>
inline void pt(T x) {
	if (x <0) {
		putchar('-');
		x = -x;
	}
	if (x>9) pt(x / 10);
	putchar(x % 10 + '0');
}
typedef long long ll;
typedef pair<ll, ll> pii;
const int inf = 1e9;
const int N = 21;
int n, m;
char s[N][N];
int a[N][N];
int dp[1 << N];
int bit[N][N], cost[N][N];
int main() {
	rd(n); rd(m);
	for (int i = 0; i < n; i++)scanf("%s", s[i]);
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)rd(a[i][j]);
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
		{
			int ans = 0, maxn = -inf;
			for (int k = 0; k < n; k++)
				if (s[i][j] == s[k][j])
				{
					ans += a[k][j];
					maxn = max(maxn, a[k][j]);
					bit[i][j] |= 1 << k;
				}
			ans -= maxn;
			cost[i][j] = ans;
		}
	for (int i = 1; i < (1 << n); i++)dp[i] = inf;
	dp[0] = 0;
	for (int i = 0; i < (1 << n); i++)
	{
		for (int j = 0; j < n; j++)
			if ((i & (1 << j)) == 0)
			{
				for (int k = 0; k < m; k++)
				{
					dp[i | (1 << j)] = min(dp[i | (1 << j)], dp[i] + a[j][k]);
					dp[i | bit[j][k]] = min(dp[i | bit[j][k]], dp[i] + cost[j][k]);
				}
			}
	}
	pt(dp[(1 << n) - 1]);
	return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-04 22:52:25

Codeforces 544E Remembering Strings 状压dp的相关文章

CodeForces 21D Traveling Graph 状压dp+欧拉回路

题目链接:点击打开链接 题意: 给定n个点m条边的无向图 求从1点开始经过每条边至少一次最后回到1点的最小路程 显然就是找一条路径可重复的欧拉回路 思路: 首先对于欧拉回路的结论是:所有点的度数都为偶数 因为所有边至少经过一次,那么可以把题意转换成加最少多少条边使得图满足以上结论 而加的边目的是为了把奇度数转成偶度数,先floyd一下得到任意点间加边的最小花费 dp[i]表示状态i下度数都为偶数的最小花费. 状压dp,把i状态下,所有未选择的点中挑2个奇度数的转移即可. #include <cs

Codeforces 482C. Game with Strings 状压DP

很好的状压dp题目 d[mask]=x   在询问了mask位的情况下,有x状态的串还是不能区分 /// 预处理不好会TLE dp[x]  从一次也没有问,到问到状态x时的概率 可以看 http://blog.csdn.net/houserabbit/article/details/40658791 大神的题解 C. Game with Strings time limit per test 1 second memory limit per test 256 megabytes input s

Codeforces 580D-Kefa and Dishes(状压DP)

原题链接:http://codeforces.com/problemset/problem/580/D 题意:在n个数字中有顺序地选择m个数字,每个数字对应有个值ai,每取一个数字答案加上ai,并且存在k个关系:x y c,如果x恰好排在y的前面,那么答案再加上ci的值.输出最大值. 思路:状压dp.dp[i][j]中,i是已经选了若干个数的情况,j是最后一个被选取的数,i从选取1个到m个枚举下去,j从第1个数到第n个数进行枚举就能得到答案. AC代码: 1 #include<iostream>

COdeforces#417D Cunning Gena(状压DP)

A boy named Gena really wants to get to the "Russian Code Cup" finals, or at least get a t-shirt. But the offered problems are too complex, so he made an arrangement with his n friends that they will solve the problems for him. The participants

CodeForces 327E Axis Walking(状压DP+卡常技巧)

Iahub wants to meet his girlfriend Iahubina. They both live in Ox axis (the horizontal axis). Iahub lives at point 0 and Iahubina at point d. Iahub has n positive integers a1, a2, ..., an. The sum of those numbers is d. Suppose p1, p2, ..., pn is a p

CF482C Game with Strings (状压DP+期望DP)

题目大意:甲和乙玩游戏,甲给出n(n<=50)个等长的字符串(len<=20),然后甲选出其中一个字符串,乙随机询问该字符串某一位的字符(不会重复询问一个位置),求乙能确定该串是哪个字符串的询问次数的期望值 这题不看题解好难想......(感谢zhx和zhx两位大佬的题解) len很小,考虑状压DP,显然我们要状压询问,要定义两个状态,f[]和num[] 1表示询问,0表示未询问 那么,我们定义f[s]表示询问状态s距离确定一个字符串所需要的期望值. 定义tot是s状态剩余的询问的次数,那么显

Codeforces 327E Axis Walking (状压dp lowbit优化)

E. Axis Walking time limit per test:3 seconds memory limit per test:512 megabytes Iahub wants to meet his girlfriend Iahubina. They both live in Ox axis (the horizontal axis). Iahub lives at point 0 and Iahubina at point d. Iahub has n positive integ

[CF544E]Remembering Strings_状压dp

E. Remembering Strings 题目大意: You have multiset of n strings of the same length, consisting of lowercase English letters. We will say that those strings are easy to remember if for each string there is some position i and some letter c of the English

CodeForces 907E Party(bfs+状压DP)

Arseny likes to organize parties and invite people to it. However, not only friends come to his parties, but friends of his friends, friends of friends of his friends and so on. That's why some of Arseny's guests can be unknown to him. He decided to