您的位置:首页 > 其它

POJ 1850 Code

2015-08-15 10:35 309 查看
Code

Time Limit: 1000MSMemory Limit: 30000KB64bit IO Format: %I64d & %I64u
Submit Status

Description

Transmitting and memorizing information is a task that requires different coding systems for the best use of the available space. A well known system is that one where a number is associated to a character sequence. It is considered that the words are made
only of small characters of the English alphabet a,b,c, ..., z (26 characters). From all these words we consider only those whose letters are in lexigraphical order (each character is smaller than the next character).

The coding system works like this:

• The words are arranged in the increasing order of their length.

• The words with the same length are arranged in lexicographical order (the order from the dictionary).

• We codify these words by their numbering, starting with a, as follows:

a - 1

b - 2

...

z - 26

ab - 27

...

az - 51

bc - 52

...

vwxyz - 83681

...

Specify for a given word if it can be codified according to this coding system. For the affirmative case specify its code.

Input

The only line contains a word. There are some constraints:

• The word is maximum 10 letters length

• The English alphabet has 26 characters.

Output

The output will contain the code of the given word, or 0 if the word can not be codified.

Sample Input

bf


Sample Output

55


题意:给定字符串排序规则如下:
只有小写字母,先按照长度拍,长的序号大,在按照字母字典序拍,一个串中字母是升序(自然不能有相同的字母)

a 1

b 2

c 3

......

z 26

ab 27

ac 28

...

az 51

bc 52

.....

vwxyz - 83681

现在输入字符串,求它的编号;

思路:

字符串的规律性很强,先考虑长度问题,加上长度已经固定为x,也就是说由x个字母组成的字符串(满足题目升序要求)有多少种,有26个字母选x个组成一个字符串,

种数就是组合数C(26,x),选出x个字符后排序只有一种(因为选出x个字母肯定没有重复的,既然是不同的x个字母的排列,而且必须升序,不就只有一种排列么-_-:);

那么就是C(26,x)种;对于输入的字符串计算长度为len,那么比len小的字符串比如排在它前面(题目说先按长度排序的),加到答案里既C(26,1)+C(26,2)+.....+C(26,len-1);

然后长度为len比输入字符串小的串的有多少个呢,数位dp咯,每个字母都有数字标号嘛,a对应0,z 对应25,字母位抽象成数字位(只不过数字位可以大于9,+.........+)

然后状态要保存前一位数字,因为题目要求升序,每次枚举都从前一位+1开始;

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<set>
#include<vector>
#include<map>
#include<stack>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=1e6+5;
const int INF=0x3f3f3f3f;
typedef __int64 ll;
ll dp[30][30],sum[30],c[30];
int a[30];
bool vis[30];
string s;
ll dfs(int pos,int n,int pre,int limit)//数位dp
{
//基本上是模板,pos保存当前第几位,pre保存上一位字母,然后记忆化搜索
    if(pos==n)
        return 1;
    if(limit==0 && dp[pos][pre]!=-1) return dp[pos][pre];
    int upper=limit?a[pos]:25;
    ll ans=0;
    for(int i=pre+1;i<=upper;i++)//合法的字符串是递增的
    {//所以i从pre+1,也就是比前一位大一的数开始枚举
        ans+=dfs(pos+1,n,i,limit && i==a[pos]);//最后一个参数的处理就是模板,貌似没见过别的写法的;
    }
    if(limit==0) dp[pos][pre]=ans;
    return ans;
}
void solve()
{
    int pos=0;
    for(int i=0;i<s.size();i++)
        a[pos++]=s[i]-'a';
    printf("%I64d\n",dfs(0,pos,-1,1)+sum[s.size()-1]);
}
void C()//递推组合数
{
    c[0]=1;
    int n=26;
    for(int i=1;i<=26;i++)
        c[i]=c[i-1]*(n-i+1)/i;
}
void init()
{
    sum[0]=0;
    C();
    for(int i=1;i<=11;i++)
    {
        sum[i]+=sum[i-1]+c[i];//组合数的和
    }
    memset(dp,-1,sizeof dp);//初始化放里面也是对的,数位dp的特别之处:每个数满不满足条件只与数本身有关,
    //只不过每组数据给的区间不一样使得区间外的数不被统计,
    //当然不同的题这里的处理是不一样的,数满不满足条件如果和输入有关那就只能放里面
}
int main()
{
    init();
    while(cin>>s)
    {
        int tag=0;
        for(int i=1;i<s.size();i++)
            if(s[i]<s[i-1]) tag=1;//输入的串要合法
        if(tag)
        {
            printf("0\n");
            continue;//break也行(。。。。);
        }
        solve();
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: