hdu 2577 dp

题目

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2577

题目来源:群赛(462377900)题目
     http://acm.hust.edu.cn/vjudge/contest/view.action?cid=90337#overview

简要题意:要在电脑上输入一串字母 S ,最后大写要关闭,求最少输入的按键数。

数据范围:T100;|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[i1][0]+1,dp[i1][1]+2)       =min(dp[i1][1]+2,dp[i1][0]+2)       Shift
当前位置的字符为大写时,转移方程如下,相似地推,就不赘述了:
dp[i][1]dp[i][0]=min(dp[i1][1]+1,dp[i1][0]+2)=min(dp[i1][0]+2,dp[i1][1]+2)


通过观察不难发现这个公式很好化简,设当前位置的大小写状态为 c ,则有:

dp[i][c]dp[i][1c]=min(dp[i1][c]+2,dp[i1][1c]+2)=min(dp[i1][1c]+1,dp[i1][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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值