zoukankan      html  css  js  c++  java
  • 搜索和组合数学P1246 编码

      题目链接P1246 编码

    题意简述

    • 要求给字符串按照规定编号,字符串长度小于等于 (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;
    }
    

      还有问题的可以评论。

  • 相关阅读:
    codeforces
    codeforces
    HDU
    poj
    poj
    HDU Problem
    HDU 3555 Bomb 【数位dp】
    POJ 1942 Paths on a Grid【组合数学】
    杭电 Problem 2089 不要62 【数位dp】
    codeforces 486c-Palindrome Transformation【贪心】
  • 原文地址:https://www.cnblogs.com/ailanxier/p/13574500.html
Copyright © 2011-2022 走看看