2 ab abcdefghijklmnopqrstuvwxyzzyxwvutsrqponmlkjihgfedcba
Case #1: 1 24 Case #2: 3 6201
给你一个串,输出不是这个串子串的最小长度和这个长度且不是这个串子串的个数。
用pre[i][j]代表第i个位置之前最后一次出现字母j(0对应a)的地方,dp1[i]表示从1到i-1这个串的最小长度,dp2[i]表示1到i-1这个串不包含的最小长度的串的个数。对于每个i,枚举满足条件的串的最后一个字母j,如果dp1[pre[i][j]]+1<dp1[i],就更新dp1[i],同时dp2[i]=dp2[pre[i][j]],如果dp1[pre[i][j]]+1==dp1[i],就让dp2[i]加上dp2[pre[i][j]]。这样做是因为假设以j结尾,那么对于当前i来说,在pre[i][j]之前的满足的串后面加上j肯定不会是1到i-1这一段的子串,并且pre[i][j]+1到i-1之间没有出现字母j,所以也不会是这一段的子串。也有贪心的思想吧,这样是能保证满足的情况下最短的。
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<vector> #include<cmath> #include<queue> #include<stack> #include<map> #include<set> #include<algorithm> #pragma comment(linker, "/STACK:102400000,102400000") using namespace std; typedef long long LL; const LL MAXN=100010; const LL INF=0x3f3f3f3f; const LL MOD=1000000007; LL T; LL pre[MAXN][30],dp1[MAXN]; LL dp2[MAXN]; char str[MAXN]; int main(){ freopen("in.txt","r",stdin); scanf("%I64d",&T); int cas=0; while(T--){ scanf("%s",str+1); LL len=strlen(str+1); memset(pre,0,sizeof(pre)); for(LL i=2;i<=len+1;i++){ for(LL j=0;j<26;j++) pre[i][j]=pre[i-1][j]; pre[i][str[i-1]-'a']=i-1; } memset(dp1,INF,sizeof(dp1)); memset(dp2,INF,sizeof(dp2)); dp1[0]=0; dp2[0]=1; for(LL i=1;i<=len+1;i++) for(LL j=0;j<26;j++){ LL k=pre[i][j]; if(dp1[i]>dp1[k]+1){ dp1[i]=dp1[k]+1; dp2[i]=dp2[k]; } else if(dp1[i]==dp1[k]+1) dp2[i]=(dp2[i]+dp2[k])%MOD; //} } printf("Case #%d:\n%I64d %I64d\n",++cas,dp1[len+1],dp2[len+1]); } return 0; }