P1246 编码

编码

题目描述

编码工作常被运用于密文或压缩传输。
这里我们用一种最简单的编码方式进行编码:把一些有规律的单词编成数字。

字母表中共有26个字母{a,b,…,z},这些特殊的单词长度不超过6且字母按升序排列。
把所有这样的单词放在一起,按字典顺序排列,一个单词的编码就对应着它在字典中的位置。

例如:a→1 b→2 z→26 ab→27 ac→28

你的任务就是对于所给的单词,求出它的编码。

输入格式

仅一行,被编码的单词。

输出格式

仅一行,对应的编码。如果单词不在字母表中,输出0。

样例 #1

样例输入 #1

ab

样例输出 #1

27

分析

  • 计算出总方案数量: \(\sum_{i=1}^{6}{C_{26}^{i}}=313911\).
  • 数据不大,可以直接搜索,\(dfs\) 得到全部组合情况,使用 \(map\) 映射记录答案.
  • 也可以用组合数学,先计算长度为 \([1,n-1]\) 的能编号字符串的总数,再计算长度为 \(n\) 的情况.
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=27, INF=0x3f3f3f3f;
string s;
map<string,int> mp;
int cnt=0,c[N][N];

void dfs(int n,int m) {
    if(m>n) {
        mp[s] = ++cnt; return;
    }
    char p='a';
    if(m>=2) p=s[m-2]+1;
    for(; p<='z'; p++) {
        s[m-1] = p;
        dfs(n,m+1);
    }
}

void C(int n) {
    for(int i=0; i<=n; i++) c[i][0]=1;
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=i; j++) {
            c[i][j]=c[i-1][j]+c[i-1][j-1];
        }
    }
}
int slove2() {
    int n=s.size(), ans=0;
    for(int i=0; i+1<n; i++) {
        if(s[i]>=s[i+1]||n>6) return 0;
    }
    C(26);
    for(int i=1; i<n; i++) ans+=c[26][i];
    for(int i=0; i<n; i++) {
        char p='a';
        if(i>=1) p=s[i-1]+1;
        for(; p<s[i]; p++) {
            ans += c['z'-p][n-1-i]; // s[i]=p的情况下,后面元素的方案数
        }
    }
    return ans+1; // 加上自身
}
int main() {
//    freopen("data.in", "r", stdin);
//    freopen("data.out", "w", stdout);
//    for(int i=1; i<=6; i++) {
//        s.clear(), s.resize(i);
//        dfs(i,1);
//    }
//    for(int i=1; i<=6; i++) {
//        for(auto it:mp)  if(it.first.size()==i)
//            cout<<it.first<<" "<<it.second<<endl;
//    }
//    while(cin>>s) cout<<mp[s];
    while(cin>>s) cout<<slove2();
    return 0;
}
posted @ 2022-10-10 10:20  HelloHeBin  阅读(119)  评论(0)    收藏  举报