搜索和组合数学P1246 编码

  题目链接P1246 编码

题意简述

  • 要求给字符串按照规定编号,字符串长度小于等于 \(6\)
  • 能编号的字符串的字母一定是递增的,规定:
    • \(\mathrm{a}\rightarrow 1\)

    • \(\mathrm{b}\rightarrow 2\)

      \(\cdots\)

    • \(\mathrm{z}\rightarrow 26\)

    • \(\mathrm{ab}\rightarrow 27\)

    • 最后一个编号 \(\mathrm{uvwxyz}\rightarrow313911\)

  • 如果给出的字符串字母不递增,则输出 \(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;
}

  还有问题的可以评论👻。

posted @ 2020-08-28 15:01  ailanxier  阅读(195)  评论(0编辑  收藏  举报