• HDU 4352 XHXJ's LIS


    XHXJ's LIS

    http://acm.hdu.edu.cn/showproblem.php?pid=4352

    题意:

      询问L~R之间多少个数满足以下条件:将数字的每一位上的数字写成一个序列(这个序列每个数不超过10,长度不超过20),然后这个序列的最长上升子序列的长度为k。

    分析:

      数位dp。

      这个状态有点特殊。首先考虑nlogn求最长上升子序列的过程,记录每长度为k上升子序列中结尾的最小的是谁。那么可以记录这个数组,每次转移更新数组即可。但是直接记录是空间开不下。但是发现这个题有一个性质:最大长度为10,最大的数字为10,而且是上升的。如果记入一个长度为10的01串。第b位上的,是从头开始第a个1,表示长度为a的最长上升子序列的结尾最小的数是b。由于是上升的,每个位上只有一个1,而且长度为10,刚好开得下。

      加入一个数后,找到第一个比它大的数,然后去掉这个,加上新加的。

    代码:

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<cmath>
     5 #include<iostream>
     6 #include<cctype>
     7 #include<set>
     8 #include<vector>
     9 #include<queue>
    10 #include<map>
    11 #define fi(s) freopen(s,"r",stdin);
    12 #define fo(s) freopen(s,"w",stdout);
    13 using namespace std;
    14 typedef long long LL;
    15 
    16 inline LL read() {
    17     LL x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    18     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
    19 }
    20 
    21 int a[22], tot, k;
    22 LL dp[22][(1 << 10) + 5][11];
    23 
    24 int getnxt(int i,int s) {
    25     for (int j=i; j<=9; ++j) 
    26         if ((1 << j) & s) { s ^= (1 << j); break; }
    27     return s | (1 << i); // !!!
    28 }
    29 int getbit(int x) {
    30     int res = 0;
    31     while (x) res += (x & 1), x >>= 1;
    32     return res;
    33 }
    34 LL dfs(int x,int sta,bool lim,bool fir) {
    35     if (!x) return getbit(sta) == k;
    36     if (!lim && dp[x][sta][k] != -1)  return dp[x][sta][k];
    37     LL res = 0;
    38     int u = lim ? a[x] : 9;
    39     for (int i=0; i<=u; ++i) 
    40         res += dfs(x - 1, fir&&i==0 ? 0 : getnxt(i, sta), lim&&i==a[x], fir&&i==0);
    41     if (!lim) dp[x][sta][k] = res;
    42     return res;
    43 }
    44 LL Calc(LL x) {
    45     tot = 0;
    46     while (x) {
    47         a[++tot] = x % 10;
    48         x /= 10;
    49     }
    50     return dfs(tot, 0, 1, 1);
    51 }
    52 int main() {
    53     memset(dp, -1, sizeof(dp));
    54     int T = read();
    55     for (int t=1; t<=T; ++t) {
    56         LL L = read(), R = read(); k = read();
    57         printf("Case #%d: ",t);
    58         printf("%lld
    ", Calc(R) - Calc(L - 1));
    59     }
    60     return 0;
    61 }
  • 相关阅读:
    存储过程加密
    sql 指删除表,改表名,改字段名
    windows 2003 server 64 位 IIS 6下部署 32位网站
    linux查看内存的使用占比
    linux查看端口是否被占用
    ERROR 2002 (HY000): Can't connect to local MySQL server through socket ‘/var/lib/mysql/mysql.sock' (2)
    mysql数据库的备份(mysqldump)和恢复(source)
    linux解压压缩文件zip/tar/tar.gz命令汇总
    oracle数据库的备份和导入数据
    oracle 备份表数据
  • 原文地址:https://www.cnblogs.com/mjtcn/p/9715469.html
Copyright © 2020-2023  润新知