题目
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2577
题目来源:群赛(462377900)题目
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=90337#overview简要题意:要在电脑上输入一串字母 S ,最后大写要关闭,求最少输入的按键数。
数据范围:
T≤100;|S|≤100 只含大小写
题解
首先想到的是直接模拟,应该很多人都会有这样的第一感觉。
对每个最长大写子串 S′ 对加上 min(2+|S′|,2|S′|) ,对于小写字母直接加。
但是这个WA了一发之后就很容易发现不对了,其实可以在大写开启的时候按Shift的。
接下来就很容易想到可以用dp来解决这个问题了。
考虑每位的状态可能是大写或小写, dp[i][j] 即为打完前 i 个字符状态为
j 的最少按键数。
不妨让 0 表示小写,1 表示大写。再考虑状态之间的转移,分情况稍微讨论一下就行了。
当前位置的字符为小写时,转移方程如下:
dp[i][0]dp[i][1]=min(dp[i−1][0]+1,dp[i−1][1]+2) 小写到小写按一下,大写到小写切换再按一下=min(dp[i−1][1]+2,dp[i−1][0]+2) 大写到大写要按Shift,小写到大写先按再切换当前位置的字符为大写时,转移方程如下,相似地推,就不赘述了:
dp[i][1]dp[i][0]=min(dp[i−1][1]+1,dp[i−1][0]+2)=min(dp[i−1][0]+2,dp[i−1][1]+2)
通过观察不难发现这个公式很好化简,设当前位置的大小写状态为 c ,则有:
dp[i][c]dp[i][1−c]=min(dp[i−1][c]+2,dp[i−1][1−c]+2)=min(dp[i−1][1−c]+1,dp[i−1][c]+2) 最终的答案为 dp[|S|][0]
实现
这个真心没啥好说的,直接推就行了,唯一值得一说的点就是
islower(char ch)
这一类函数的返回值其实是int
,我这种喜欢直接赋值过去的就比较容易被坑了,总结下来还是需要多了解系统的函数。复杂度 Θ(|S|) 。
朴素代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
LL powmod(LL a,LL b, LL MOD) {LL res=1;a%=MOD;for(;b;b>>=1){if(b&1)res=res*a%MOD;a=a*a%MOD;}return res;}
// head
const int INF = 0x3f3f3f3f;
char s[105];
int dp[105][2];
int main()
{
int t;
scanf("%d", &t);
while (t--) {
scanf("%s", s+1);
int len = strlen(s+1);
bool flag = false;
memset(dp, INF, sizeof dp);
dp[0][0] = 0;
for (int i = 1; i <= len; i++) {
if (islower(s[i])) {
dp[i][0] = min(dp[i-1][0]+1, dp[i-1][1]+2);
dp[i][1] = min(dp[i-1][1]+2, dp[i-1][0]+2);
} else {
dp[i][1] = min(dp[i-1][1]+1, dp[i-1][0]+2);
dp[i][0] = min(dp[i-1][0]+2, dp[i-1][1]+2);
}
}
printf("%d\n", dp[len][0]);
}
return 0;
}
化简代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
LL powmod(LL a,LL b, LL MOD) {LL res=1;a%=MOD;for(;b;b>>=1){if(b&1)res=res*a%MOD;a=a*a%MOD;}return res;}
// head
const int INF = 0x3f3f3f3f;
char s[105];
int dp[105][2];
int main()
{
int t;
scanf("%d", &t);
while (t--) {
scanf("%s", s+1);
int len = strlen(s+1);
bool flag = false;
memset(dp, INF, sizeof dp);
dp[0][0] = 0;
for (int i = 1; i <= len; i++) {
int c = islower(s[i]) ? 1 : 0;
dp[i][c] = min(dp[i-1][c], dp[i-1][1-c])+2;
dp[i][1-c] = min(dp[i-1][1-c]+1, dp[i-1][c]+2);
}
printf("%d\n", dp[len][0]);
}
return 0;
}