1071: zdw的嘤嘤嘤
时间限制: 1 Sec 内存限制: 128 MB提交: 53 解决: 14
[ 提交][ 状态][ 讨论版]
题目描述
//感觉会被zdw揍
众所周知,zdw是一个萌妹,喜欢嘤嘤嘤。而且最擅长八重嘤和嘤雄不朽。
这一天zdw说了一个很长的字符串,只包括 ‘y’ , ‘i’ , ‘n’ ,’g’这四个字符。你需要选取尽量多的下标,让这些下标在这个字符串中对应的字符按下标从小到大的顺序组起来是一个”yyyyiiinngggg”这样的字符串。其中’y’,’i’,’n’,’g’这些字符的个数为0也算是合法的。比如”yngg”和”g”都是合法的答案
现在cy想知道,最多能选多少下标,令其合法?
输入数据:
第一行一个T,表示有T组数据
T行每行一个字符串,只包含’y’, ’i’ , ’n’ , ’g’这四个小写字母
输出:
T行每行一个整数,代表最多能选取多少下标。
数据范围
T<=10
对于30%的数据:|s|<=10;
对于另10%的数据:只包含一种字母,|s|<=100000;
对于100%的数据:|s|<=100000
样例1:
INPUT
1
ygniyging
OUTPUT
5
样例2:
INPUT
2
y
ing
OUTPUT
1
3
输入
输出
提示
来源
题意: 按照给出的序列顺序,你需要选取尽量多的下标,让这些下标在这个字符串中对应的字符按下标从小到大的顺序组起来是一个”yyyyiiinngggg”这样的字符串。其中’y’,’i’,’n’,’g’这些字符的个数为0也算是合法的。比如”yngg”和”g”都是合法的答案;
思路:可以用求最长非严格单调递增序列的 dp方法写,upper_bound(), 但是还可以用另一种思想写:也是dp思想,但是和前一种不一样,一定要好好理解一下;
方法一:dp,好好理解一下;
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#include<map>
#define Max 100010
char str[Max];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s",str);
int l = strlen(str);
int y = 0,yi = 0,yin = 0,ying = 0;
for(int i = 0;i<l;i++)
{
if(str[i]=='y')
y++;
else if(str[i]=='i')
yi++;
else if(str[i]=='n')
yin++;
else if(str[i]=='g')
ying ++;
yi = max(y,yi);
yin = max(yi,yin);
ying = max(yin,ying);
}
printf("%d\n",ying);
}
return 0;
}
方法二:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#include<map>
#define Max 100010
#define INF 0x3f3f3f3f
char str[Max];
int dp[Max]; // dp[i] 为长度为 i+1 的上升子序列中末尾元素的最小值;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s",str);
int l = strlen(str);
//int y = 0,yi = 0,yin = 0,ying = 0;
memset(dp,INF,sizeof(dp));
int tt;
for(int i = 0;i<l;i++)
{
if(str[i]=='y')
tt = 1;
else if(str[i]=='i')
tt = 2;
else if(str[i]=='n')
tt = 3;
else if(str[i]=='g')
tt = 4;
*upper_bound(dp,dp+l,tt) = tt;
}
printf("%d\n",upper_bound(dp,dp+l,4) - dp);
}
return 0;
}