zoukankan      html  css  js  c++  java
  • HDU 5632 Rikka with Array [想法题]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5632

    ------------------------------------------------------------------------------------------

    这场比赛的官方题解说这题比较明显, 然而我比赛完后对着题解看了好久也没有想明白

    于是先做了几道数位$DP$找找感觉 可惜感觉并没有找到

    这题和传统数位$DP$不一样 这题是求范围内满足要求的数对的个数

    既然是数对 我们记录时便不再记录数的状态 而是记录两数之间的关系的状态

    不过官方题解只记录 考虑到了哪位 两数$1$的个数差的绝对值

    大数$1$的个数是否不小于小数$1$的个数 这三个部分

    可惜自己做的时候总感觉只记录这些状态还不够

    然后$Cwind$前辈提供了一个思路 额外记录两个部分

    大小两数当前位之前是否相等 大数当前位之前是否与限制条件相等

    ------------------------------------------------------------------------------------------

    用以上的思路就可以比较轻松的用记忆化搜索做了

    不过由于状态多两维 而且一开始的写法每次询问都需要重新计算 因而时间比较挫 要$1.4s$

    观察后可发现如果较大数的当前位之前于限制条件不等 那么后面的数的选取都是任意的

    所以这种情况下并不用每次重新计算 加了这个常数优化后要 $0.6s$

    再加上一个对于当前状态贡献一定是$0$的剪枝后还要$0.48s$

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <cmath>
     4 #include <algorithm>
     5 using namespace std;
     6 const int N = 1000, mod = 998244353;
     7 int f[N][N][2][2][2], cnt[N][N][2][2][2];//cnt记录的是时间戳
     8 bool bin[N];
     9 int num[310];
    10 char s[310];
    11 int t, len, n;
    12 void init()
    13 {
    14     n = 0;
    15     while(len)
    16     {
    17         for(int i = len; i; --i)
    18         {
    19             num[i - 1] += (num[i] & 1) * 10;
    20             num[i] >>= 1;
    21         }
    22         bin[++n] = (num[0] != 0);
    23         num[0] = 0;
    24         if(!num[len])
    25             --len;
    26     }
    27 }
    28 int dfs(int x, int dif, bool over, bool same, bool top)
    29 {
    30     if(cnt[x][dif][over][same][top] == t + 1 || 
    31     (cnt[x][dif][over][same][top] && !top))
    32         return f[x][dif][over][same][top];
    33     cnt[x][dif][over][same][top] = t + 1;
    34     if(!x)
    35         return f[x][dif][over][same][top] = !over;
    36     if(over && dif >= x)
    37         return f[x][dif][over][same][top] = 0;
    38     int re = 0;
    39     if(!top || bin[x])
    40     {
    41         re += dfs(x - 1, dif, over, same, top);
    42         re += dfs(x - 1, dif + (over ? 1 : -1), over || dif == 1, 0, top);
    43         re = (re >= mod ? re - mod : re);
    44     }
    45     if(!same)
    46     {
    47         re += dfs(x - 1, abs(dif + (over ? -1 : 1)), over && dif, 0, top && !bin[x]);
    48         re = (re >= mod ? re - mod : re);
    49     }
    50     re += dfs(x - 1, dif, over, same, top && !bin[x]);
    51     re = (re >= mod ? re - mod : re);
    52     return f[x][dif][over][same][top] = re;
    53 }
    54 int main()
    55 {
    56     scanf("%d", &t);
    57     while(t--)
    58     {
    59         scanf("%s", s + 1);
    60         len = strlen(s + 1);
    61         for(int i = 1; i <= len; ++i)
    62             num[i] = s[len - i + 1] - '0';
    63         init();
    64         printf("%d
    ", dfs(n, 0, 1, 1, 1));
    65     }
    66     return 0;
    67 }

    想到/理解了 更好的方法再来改改吧

  • 相关阅读:
    Linux中./configure、make、make install详解
    VMware虚拟CentOS 6.5在NAT模式下配置静态IP地址及Xshell远程控制配置
    VMWare中Linux虚拟机设置静态IP上网的设置方法
    Linux下SSH远程连接断开后让程序继续运行解决办法
    弱网测试(一)
    算法的测试
    前端图片加载优化
    jpg/jpeg/png格式的区别与应用场景
    测试分类标准
    Mysql 日期与时间戳的相互转化
  • 原文地址:https://www.cnblogs.com/sagitta/p/5225991.html
Copyright © 2011-2022 走看看