题意简述
- 要求给字符串按照规定编号,字符串长度小于等于 (6) 。
- 能编号的字符串的字母一定是递增的,规定:
-
(mathrm{a} ightarrow 1)
-
(mathrm{b} ightarrow 2)
(cdots)
-
(mathrm{z} ightarrow 26)
-
(mathrm{ab} ightarrow 27)
-
最后一个编号 (mathrm{uvwxyz} ightarrow313911)
-
- 如果给出的字符串字母不递增,则输出 (0) ,否则输出对应编号。
暴力枚举
首先数据范围很小。先简单算一下,用组合数计算出每一个长度能编号的字符串数目。
- 长度为 (1) 能编号的字符串数目为 (C_{26}^1 = 26)
- 长度为 (2) 能编号的字符串数目为 (C_{26}^2 = 325)
把 (6) 个组合数加起来编号就是 (313911) ,即最后一个字符串 (mathrm{uvwxyz}) 的编号,完全可以枚举每一个可以编号的字符串,找到匹配的就输出编号即可,否则输出 (0)。
(mathrm{Code}):
#include <bits/stdc++.h>
#define FOR(i,a,b) for(int i = a;i <= b;i++)
using namespace std;
char s[10],test[10];//s记录询问的字符串,test记录尝试的字符串
int n,id; //n记录询问字符串长度,id为编号
//last记录前一个字母,step记录递归层数,枚举下一位
void dfs(char last, int step){
if(!step) return;
for (char i = last + 1; i <= 'z'; i++) {
test[step] = i;
if(step == 1) {
id++; //枚举到最后一位编号才加一
int flag = 1;
FOR(j,1,n) if(s[j] != test[n - j + 1]) flag = 0; //逐位比对,注意test是逆着记录的
if(flag) {cout << id;exit(0);}
}
dfs(i,step-1);
}
}
signed main(){
scanf("%s", s + 1);
n = strlen(s + 1);
FOR(i,1,n)
dfs('a'-1,i);
cout<<0; //在dfs中未找到,说明字符串不满足要求
return 0;
}
组合数学
这题如果数据量较大可以用组合数学解决。我们先算出长度为 (1)~ (n-1) 的能编号字符串的总数,最后再解决长度为 (n) 的字符串情况。涉及的细节可能比较多,我尽可能注释了。
(mathrm{Code}):
#include <bits/stdc++.h>
#define FOR(i,a,b) for(int i = a;i <= b;i++)
using namespace std;
char s[10];//ch记录询问的字符串
int n,id,c[30][30]; //n记录询问字符串长度
signed main(){
FOR(i,0,26) c[i][0] = 1;
FOR(i,1,26) FOR(j,1,26) c[i][j] = c[i-1][j]+c[i-1][j-1];//组合数递推式,
scanf("%s", s + 1);
n = strlen(s + 1);
//处理长度小于n的字符串编号
FOR(i,1,n-1) {
if(s[i] >= s[i+1]) {
cout<<0;//不升序排列就直接输出0
exit(0);
}
id += c[26][i]; //从26个字母中选i个,一定可以排成递增的字符串
}
int j ;
FOR(i,1,n){
//j要分情况赋值,前i-1位已固定为s[1]到s[i-1](i != 1)
if(i == 1) j = 'a';
else j = s[i-1]+1;
for(;j < s[i];j++)
id += c['z'-j][n-i]; //在第i位为字母j的情况下,后面n-i位的组合情况。
}
cout<<id+1; //记得加一
return 0;
}
还有问题的可以评论。