您的位置:首页 > 其它

ZOJ 3985 String of CCPC 2017秦皇岛CCPC(子串个数)

2017-11-02 18:31 381 查看
传送门ZOJ 3985

题意:给你一个只含字符 'C' 和 'P' 的字符串,我们可以购买字符 'C' 和 'P'并插入字符串的任意位置,购买第 x 个字符的花费为 x-1,问字符串中“CCPC”子串数 - 花费数最大为多少。

思路:只有在字符串中含有 "CCPPC" 的时候可以在第一个 'P' 之后插入两个 'C' 这样会产生 2 个 "CCPC"子串,花费为 1,这样的净利润是 1.其他情况最多新产生 1 个 "CCPC" 子串。所以,最多插入 2 个字符,否则利润就成负的了。

从上面的分析可以看出,可以插入 1 或 2 个字符,最大的利润也就是 1,那么什么时候能多产生 1 的利润呢?也就是当我们插入字符使得形成新的 "CCPC" 串的时候。当字符串中有 "CCPPC"时,插入 “CC” ,当字符串中有 "CCC"、"PCPC"、"CCPP"时插入一个 'C'。还有前缀为 "CPC" 或后缀为 "CCP"时也可以。

桥都麻袋,是不是有什么地方不对?如果字符串中含有 "CCPCCCPC" 时,是含有 "CCC" 的,但是这时候如果插入一个 'P' 就会破坏了原来的串,所以判断条件应该是看是否有 “CCCC”。这样一来还要加上判断后缀是否是 "CCC"。

还有一点就是前面为什么判断是否含有 "CCPP" 这么麻烦,直接判断 "CCP" 不就可以了吗?当然不是因为如果原串是 "CCPC" 则也含有 "CCP",你插入一个 'C' 毫无影响。

你可能会说,要判断是否含有这么多子串,要怎么想啊。很简单,就是写出 "CCPC" 中任意字符被另一字符替换后可能出现的结果就可以了。

具体实现:先用 KMP 寻找字符串中 "CCPC" 的数量,然后再判断是否符合上面说的那些条件,如果符合则结果 +1。

代码

#include<stdio.h>
#include<string.h>

int l1,l2,next[10];
char s[200010],t[10];

void pnext()
{ //未经优化的求next数组方法
int i=0,j=-1;
next[0] = -1;
while(i<l2)
{
if(j==-1||t[i]==t[j])
{
i++;
j++;
next[i]=j;
}
else j=next[j];
}
}

int kmp()
{
int i
4000
=0,j=0,sum=0;	//多了个计数变量sum
pnext();
while(i<l1)  //只需要目标串指针小于目标串长度即可,这点和单纯的kmp不一样
{
if(s[i]==t[j] || j==-1)
{
i++;
j++;
}
else if(j<l2) j = next[j];
if(j>=l2)
{
sum++;
j=next[j];
}
}

return sum;
}

int main()
{
int i,tt,n,ans;
scanf("%d",&tt);
while(tt--)
{
scanf("%d",&n);
scanf("%s",s);
if(n<3)
{ //如果长度 <3 则结果为 0
printf("0\n");
continue;
}
l1=n;
l2=4;
strcpy(t,"CCPC");
ans=kmp(); //求字符串中 "CCPC" 的数量
//判断是否含有某些特定的子串或前缀和后缀是否满足条件
if(strstr(s,"CCCC")!=NULL||strstr(s,"PCPC")!=NULL
||strstr(s,"CCPP")!=NULL||strstr(s,"CCPPC")!=NULL
||(s[0]=='C'&&s[1]=='P'&&s[2]=='C')
||(s[n-3]=='C'&&s[n-2]=='C'&&s[n-1]=='P')
||(s[n-3]=='C'&&s[n-2]=='C'&&s[n-1]=='C')) ans++;
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: