您的位置:首页 > 其它

SDUT OJ 2607

2013-08-14 15:07 204 查看
/*http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2607*/
题目大意:给出一个字符串,求出里面为山字形的子序列,比如1 2 1,给出的字符串都是
小写字母组成,大小按照码值判断,问里面有几个这样的子序列,保证长度大于等三,且中点左右必须至少有一个字符。注意:相同的两个算两个
比如acca算aca和aca两个,其中c的下标分别为1和2。
解法:既然是左边递增右边递减,那么我们左右都求一次递增子序列的个数,然后相乘就是相加就是所有的组合数
因为字母只有26个,那么时间复杂度为O(26*n);
建立一个hash字母表记录到小标i为止前面出现过的以每个字母结尾的递增子序列个数,单个不算
比如:abca,到小标2时枚举hash表的0到1,以前求出的hash[0]=1,hash[1]为2,那么hash[2]=3,虽然单个的不算,但是每次算完dp[i]
的值要加上s[i]这一个单词以保证后面的字母加上s[i]可以得到一个长度大于等于2的子序列
,然后逆着再做一遍,就可算出正着的和逆序的以每个字母结尾的长度在二和二以上的

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int dp[100010];
char s[100010];
int hash[30];
int main()
{
int i,j,n,c;
long long sum,ok;
while(scanf("%d",&n)!=EOF)
{
scanf("%s",s);
memset(hash,0,sizeof(hash));
for(i=0;i<n;i++)
{
dp[i]=0;
c=s[i]-'a';
for(j=0;j<c;j++)
{
dp[i]+=hash[j];
dp[i]=dp[i]%2012;
}
hash[c]+=dp[i]+1;//加1,相当于加上s[i]这个字母
hash[c]=hash[c]%2012;
}
memset(hash,0,sizeof(hash));
sum=0;
for(i=n-1;i>=0;i--)
{
c=s[i]-'a';
ok=0;
for(j=0;j<c;j++)
{
ok+=hash[j];
ok=ok%2012;
}
hash[c]+=ok+1;
hash[c]=hash[c]%2012;
sum=sum+(dp[i]*ok);
sum=sum%2012;
}
printf("%lld\n",sum);
}
return 0;
}

/**************************************
Problem id    : SDUT OJ 2607
User name    : ORC
Result        : Accepted
Take Memory    : 756K
Take Time    : 150MS
Submit Time    : 2013-08-14 14:45:07
**************************************/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: