CF761C Dasha and Password(线性dp)

洛谷链接
https://www.luogu.com.cn/problem/CF761C

题目大意

给n个字符串,每个长m,初始光标都在每个字符串的开头位置,通过移动光标,从n个字符串中各选择一个字符,构成密码,(移动光标时把长度为m的字符串当做一个环),密码必须满足有至少一个小写字母,至少一个数字,至少一个其他字符(# & *),求最小移动次数。

数据范围

3<=n<=50,1<=m<=50

Solution
O(n^3)
令dp[i][j] 为第i行选择j类字符的最小移动次数
(j == 1 数字)
(j == 2 小写字母)
(j == 3 其他符号)
把每一行单独处理,最后枚举统计最小的答案。
答案为min(dp[i][1] + dp[j][2] + dp[k][3])
!!!注意极大值,防止dp[i][j]赋为极大值时,三个加起来爆int。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 1e9 + 7;
const int SZ = 100 + 5;
int n,m;//1 (0 - 9) 2 (a - z) 3 (# & *) 
char s[SZ][SZ];//dp[i][j] 第i行换成j类型的最小移动次数 
ll dp[SZ][4],ans;
int main()
{
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;i ++ )
		for(int j = 1;j <= 3;j ++ )
		dp[i][j] = INF; 
	for(int i = 1;i <= n;i ++ ) scanf("%s",s[i] + 1);
	for(int i = 1;i <= n;i ++)
	{
		for(int j = 1;j <= 3;j ++ )
		{
			for(int k = 1;k <= m;k ++ )
			{
				if(s[i][k] >= '0' && s[i][k] <= '9') dp[i][1] = min(dp[i][1],min((ll)(k - 1),(ll)(m - k + 1))); 
				if(s[i][k] >= 'a' && s[i][k] <= 'z') dp[i][2] = min(dp[i][2],min((ll)(k - 1),(ll)(m - k + 1))); 
				if(s[i][k] == '#' || s[i][k] == '*' || s[i][k] == '&' ) dp[i][3] = min(dp[i][3],min((ll)(k - 1),(ll)(m - k + 1))); 
			}
		}
	}
	ans = INF;
	for(int i = 1;i <= n;i ++ )
		for(int j = 1;j <= n;j ++ )
			for(int k = 1;k <= n;k ++ )
			{
				if(i != j && i != k && j != k)
				{
					ans = min(ans,dp[i][1] + dp[j][2] + dp[k][3]);
				}
			}
	printf("%d",ans);
	return 0;
} 	


2020.3.31

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