題意:合法字串滿足字符從左到右嚴格遞增,所有的合法字串按照優先長度遞增,其次字典序遞增排列,求給定一個字符串,是否合法,若合法,編號爲幾?
分析:依舊是數位DP的思想,預處理出長度爲i,首字母爲j的字符串個數 f [ i ] [ j ]。
給定字符串,首先加上長度小於它的字符串的個數。
然後依次枚舉第一個小於原字符串的位置,加上該位字母大於前一位、小於後一位的字符串的個數。
代碼:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<stack>
#include<queue>
#include<map>
#include<set>
using namespace std;
long long f[20][30];//長度爲i,以j開頭的字符串的個數
int num[20],len;
int initi()
{
int i,j,k;
memset(f,0,sizeof(f));
for(i=0;i<26;i++)
f[1][i]=1;
for(i=2;i<=10;i++)
{
for(j=0;j<26;j++)
{
for(k=j+1;k<26;k++)
f[i][j]+=f[i-1][k];
}
}
}
long long cal()
{
long long sum=0,i,j,k;
for(i=1;i<len;i++)
{
for(j=0;j<26;j++)
sum+=f[i][j];
}
for(i=0;i<len;i++)
{
if(i==0)
{
for(j=0;j<num[i];j++)
sum+=f[len][j];
}
else
{
for(j=num[i-1]+1;j<num[i];j++)
sum+=f[len-i][j];
}
}
return sum;
}
int main()
{
char s[20];
int yes=1,i;
initi();
scanf("%s",s);
len=strlen(s);
num[0]=s[0]-'a';
for(i=1;i<len;i++)
{
num[i]=s[i]-'a';
if(num[i]<=num[i-1])
{
yes=0;
printf("0\n");
break;
}
}
if(yes==1)
{
printf("%I64d\n",cal()+1);
}
return 0;
}