1 /*http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2607*/ 2 题目大意:给出一个字符串,求出里面为山字形的子序列,比如1 2 1,给出的字符串都是 3 小写字母组成,大小按照码值判断,问里面有几个这样的子序列,保证长度大于等三,且中点左右必须至少有一个字符。注意:相同的两个算两个 4 比如acca算aca和aca两个,其中c的下标分别为1和2。 5 解法:既然是左边递增右边递减,那么我们左右都求一次递增子序列的个数,然后相乘就是相加就是所有的组合数 6 因为字母只有26个,那么时间复杂度为O(26*n); 7 建立一个hash字母表记录到小标i为止前面出现过的以每个字母结尾的递增子序列个数,单个不算 8 比如:abca,到小标2时枚举hash表的0到1,以前求出的hash[0]=1,hash[1]为2,那么hash[2]=3,虽然单个的不算,但是每次算完dp[i] 9 的值要加上s[i]这一个单词以保证后面的字母加上s[i]可以得到一个长度大于等于2的子序列 10 ,然后逆着再做一遍,就可算出正着的和逆序的以每个字母结尾的长度在二和二以上的 11 12 #include<stdio.h> 13 #include<string.h> 14 #include<algorithm> 15 using namespace std; 16 int dp[100010]; 17 char s[100010]; 18 int hash[30]; 19 int main() 20 { 21 int i,j,n,c; 22 long long sum,ok; 23 while(scanf("%d",&n)!=EOF) 24 { 25 scanf("%s",s); 26 memset(hash,0,sizeof(hash)); 27 for(i=0;i<n;i++) 28 { 29 dp[i]=0; 30 c=s[i]-'a'; 31 for(j=0;j<c;j++) 32 { 33 dp[i]+=hash[j]; 34 dp[i]=dp[i]%2012; 35 } 36 hash[c]+=dp[i]+1;//加1,相当于加上s[i]这个字母 37 hash[c]=hash[c]%2012; 38 } 39 memset(hash,0,sizeof(hash)); 40 sum=0; 41 for(i=n-1;i>=0;i--) 42 { 43 c=s[i]-'a'; 44 ok=0; 45 for(j=0;j<c;j++) 46 { 47 ok+=hash[j]; 48 ok=ok%2012; 49 } 50 hash[c]+=ok+1; 51 hash[c]=hash[c]%2012; 52 sum=sum+(dp[i]*ok); 53 sum=sum%2012; 54 } 55 printf("%lld ",sum); 56 } 57 return 0; 58 } 59 60 61 62 63 /************************************** 64 Problem id : SDUT OJ 2607 65 User name : ORC 66 Result : Accepted 67 Take Memory : 756K 68 Take Time : 150MS 69 Submit Time : 2013-08-14 14:45:07 70 **************************************/