题意:
给出一个字符串,求这样的子串个数 a1<a2<...<ai < Amax < aj <.....<an;
题解:
要计算这样的个数,那么问题可以分解成计算上升子序列的个数和计算下降子序列的个数,然后枚举最大点。
dp[26],dpl[i],dpr[i].dp[26]表示到i为止以某个字母为结尾的上升子串个数,dpl[i],表示以s[i]为结尾的上升子串个数,dpr[i]同理。
于是状态方程:
dpl[i]=sum{ dp[j] }(s[j]<s[i])
dp[s[i]]=dpl[i]+1;
dpr[i]=sum{ dp[j] }(s[j]<s[i])
dp[s[i]]=dpr[i]+1;
#include<iostream> #include<math.h> #include<stdio.h> #include<algorithm> #include<string.h> #include<vector> #include<queue> #include<map> #include<set> #define B(x) (1<<(x)) using namespace std; typedef long long ll; void cmax(int& a,int b){ if(b>a)a=b; } void cmin(int& a,int b){ if(b<a)a=b; } void cmax(ll& a,ll b){ if(b>a)a=b; } void cmin(ll& a,ll b){ if(b<a)a=b; } void add(int& a,int b,int mod){ a=(a+b)%mod; } void add(ll& a,ll b,ll mod){ a=(a+b)%mod; } const int oo=0x3f3f3f3f; const int MOD=2012; const int maxn=110000; char str[maxn]; int dp[30],s[maxn]; int dpl[maxn],dpr[maxn]; int main(){ //freopen("E:\\read.txt","r",stdin); int n; while(scanf("%d",&n)!=EOF){ scanf("%s",str+1); for(int i=1;i<=n;i++)s[i]=str[i]-'a'; memset(dp,0,sizeof dp); memset(dpl,0,sizeof dpl); memset(dpr,0,sizeof dpr); for(int i=1;i<=n;i++){ for(int j=0;j<s[i];j++) dpl[i]=(dpl[i]+dp[j])%MOD; dp[s[i]]=(dp[s[i]]+dpl[i]+1)%MOD; } memset(dp,0,sizeof dp); for(int i=n;i>=1;i--){ for(int j=0;j<s[i];j++) dpr[i]=(dpr[i]+dp[j])%MOD; dp[s[i]]=(dp[s[i]]+dpr[i]+1)%MOD; } int ans=0; for(int i=2;i<n;i++){ ans=(ans+dpl[i]*dpr[i])%MOD; } printf("%d\n",ans); } return 0; }