• [Swust OJ 715]--字典序问题(组合数预处理/数位dp)


    题目链接:http://acm.swust.edu.cn/problem/715/

    Time limit(ms): 1000      Memory limit(kb): 65535
     
    在数据加密和数据压缩中常需要对特殊的字符串进行编码。给定的字母表A 由26 个小写英文字母组成A={a,b,…,z}。该字母表产生的升序字符串是指字符串中字母按照从左到右出现的次序与字母在字母表中出现的次序相同,且每个字符最多出现1 次。例如,a,b,ab,bc,xyz 等字符串都是升序字符串。现在对字母表A 产生的所有长度不超过6 的升序字符串按照字典序排列并编码如下。 

    1 2 … 26 27 28 …
    a b … z ab ac …


    对于给定的长度不超过6 的升序字符串,编程计算出它在上述字典中的编码。
    Description
    文件的第一行是一个正整数k,表示接下来共有k 行。 
    接下来的k行中,每行给出一个字符串。
    Input
    共有k 行,每行对应于一个字符串的编码。
    Output
    1
    2
    3
    2
    a
    b
    Sample Input
    1
    2
    1
    2
    Sample Output
     
     
    解题思路:这道题用数位dp的话不太现实(状态设计太诡异的说~~~)
         那么指定个  字母   只有一个排列合法,符合组合数的概念,可以考虑使用组合数
         然后在当前状态下,求长度小于len的总个数,等于len的当前序列的总个数(相当于把问题细化了)
         具体的看代码吧~~~
     
        值得注意的是   利用杨辉三角计算组合数   且合数性质cur[i][j]=cur[i][i-j];
     
    代码如下:
     1 #include <iostream>
     2 #include <cstring>
     3 using namespace std;
     4 
     5 char s[7];
     6 int cur[27][27] = { 1 };
     7 
     8 //预处理 利用杨辉三角计算组合数
     9 void init(){
    10     int i, left, right;
    11     for (i = 1; i <= 26; i++){
    12         cur[i][0] = cur[i][i] = 1;
    13         left = 1, right = i - 1;
    14         while (left <= right){
    15             cur[i][left] = cur[i - 1][left - 1] + cur[i - 1][left];
    16             cur[i][right--] = cur[i][left++];//组合数性质cur[i][j]=cur[i][i-j];
    17         }
    18     }
    19 }
    20 
    21 //长度小于len的串的个数
    22 int minlen_num(int len){
    23     int i, cnt = 0;
    24     for (i = 1; i < len; i++)
    25         cnt += cur[26][i];
    26     return cnt;
    27 }
    28 
    29 //当前长度下当前串前面的个数
    30 int enquallen_num(int len){
    31     int i, j, cnt = 0, pre = -1, tmp;
    32     for (i = 0; i < len; i++){
    33         tmp = s[i] - 'a';
    34         for (j = pre + 1; j < tmp; j++)
    35             cnt += cur[26 - j - 1][len - i - 1];
    36         pre = tmp;
    37     }
    38     return cnt;
    39 }
    40 
    41 bool judge(int len){
    42     for (int i = 1; i < len; i++)
    43     if (s[i] <= s[i - 1])
    44         return false;
    45     return true;
    46 }
    47 
    48 int main(){
    49     init();
    50     int t, cnt, len;
    51     cin >> t;
    52     while (t--){
    53         cnt = 0;
    54         cin >> s;
    55         len = strlen(s);
    56         if (!judge(len)) cout << 0 << endl;
    57         else{
    58             cnt += minlen_num(len);
    59             cnt += enquallen_num(len);
    60             cout << cnt + 1 << endl;
    61         }
    62     }
    63     return 0;
    64 }
    View Code

    6/18号我又回来了,这道题是可以数位dp的,当时我设计状态的时候果断逗比了~~~直接在递归时,加个判断就限制了后面数字的选取状态就可以强势ac了

    (感谢学长的指点)

    代码如下:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 using namespace std;
     5 #define ll long long
     6 #define N 110
     7 
     8 char s[N];
     9 ll bit[N];
    10 ll dp[N][N];
    11 
    12 ll dfs(ll pos, ll mx, bool limit, bool fzero)
    13 {
    14     if (pos == -1) return 1;
    15     if (!limit && !fzero && ~dp[pos][mx]) return dp[pos][mx];
    16     ll end = limit ? bit[pos] : 26;
    17     ll ans = 0;
    18     for (ll i = fzero ? 0 : mx; i <= end; i++)//这里就判断了后面的字母的选取是否有限制(题目上的升序)
    19     {
    20         ans += dfs(pos - 1, i + 1, limit && i == end, fzero && !i);
    21     }
    22     if (!limit && !fzero) dp[pos][mx] = ans;
    23     return ans;
    24 }
    25 ll cal()
    26 {
    27     ll len = strlen(s + 1);
    28     for (ll i = 1; i <= len; i++)
    29     {
    30         bit[len - i] = s[i] - 'a' + 1;
    31     }
    32     return dfs(len - 1, 0, 1, 1);
    33 }
    34 int main()
    35 {
    36     int t;
    37     cin >> t;
    38     while (t--)
    39     {
    40         memset(dp, -1, sizeof(dp));
    41         scanf("%s", s + 1);
    42         int flag = 1;
    43         int len = strlen(s + 1);
    44         for (int i = 1; i<len; i++)
    45         {
    46             if (!(s[i]<s[i + 1]))
    47             {
    48                 flag = 0;
    49                 break;
    50             }
    51         }
    52         if (!flag) printf("0
    ");
    53         else
    54             printf("%lld
    ", cal() - 1);
    55     }
    56     return 0;
    57 }
    View Code
  • 相关阅读:
    中等疾病活动度的RA患者持续传统治疗的结果:来自ERAN的数据
    中信国健临床通讯2011年1月第1期目录
    影像学是否应该纳入RA缓解标准?传统评分与修订后复合评分和影像学评估的比较
    RA患者妊娠期使用依那西普维持缓解
    TNFα拮抗剂减少脊髓损伤大鼠神经元和少突胶质细胞的凋亡
    新近起病的活动性RA患者中达标治疗与常规治疗的疗效比较:来自GUEPARD试验和ESPOIR队列的数据
    TNF抑制剂相关的肿瘤风险:阿达木单抗、依那西普和英夫利昔单抗随机对照试验的荟萃分析
    依那西普治疗日本RA患者的安全性与疗效的上市后监察
    依那西普与柳氮磺吡啶治疗强直性脊柱炎的临床疗效与安全性比较:一项随机双盲研究(ASCEND试验)
    POJ3450 Corporate Identity KMP+枚举
  • 原文地址:https://www.cnblogs.com/zyxStar/p/4564357.html
Copyright © 2020-2023  润新知