HDU 5632 Rikka with Array [想法题]
2016-02-28 23:32
344 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5632
------------------------------------------------------------------------------------------
这场比赛的官方题解说这题比较明显, 然而我比赛完后对着题解看了好久也没有想明白
于是先做了几道数位$DP$找找感觉 可惜感觉并没有找到
这题和传统数位$DP$不一样 这题是求范围内满足要求的数对的个数
既然是数对 我们记录时便不再记录数的状态 而是记录两数之间的关系的状态
不过官方题解只记录 考虑到了哪位 两数$1$的个数差的绝对值
大数$1$的个数是否不小于小数$1$的个数 这三个部分
可惜自己做的时候总感觉只记录这些状态还不够
然后$Cwind$前辈提供了一个思路 额外记录两个部分
大小两数当前位之前是否相等 大数当前位之前是否与限制条件相等
------------------------------------------------------------------------------------------
用以上的思路就可以比较轻松的用记忆化搜索做了
不过由于状态多两维 而且一开始的写法每次询问都需要重新计算 因而时间比较挫 要$1.4s$
观察后可发现如果较大数的当前位之前于限制条件不等 那么后面的数的选取都是任意的
所以这种情况下并不用每次重新计算 加了这个常数优化后要 $0.6s$
再加上一个对于当前状态贡献一定是$0$的剪枝后还要$0.48s$
想到/理解了 更好的方法再来改改吧
------------------------------------------------------------------------------------------
这场比赛的官方题解说这题比较明显, 然而我比赛完后对着题解看了好久也没有想明白
于是先做了几道数位$DP$找找感觉 可惜感觉并没有找到
这题和传统数位$DP$不一样 这题是求范围内满足要求的数对的个数
既然是数对 我们记录时便不再记录数的状态 而是记录两数之间的关系的状态
不过官方题解只记录 考虑到了哪位 两数$1$的个数差的绝对值
大数$1$的个数是否不小于小数$1$的个数 这三个部分
可惜自己做的时候总感觉只记录这些状态还不够
然后$Cwind$前辈提供了一个思路 额外记录两个部分
大小两数当前位之前是否相等 大数当前位之前是否与限制条件相等
------------------------------------------------------------------------------------------
用以上的思路就可以比较轻松的用记忆化搜索做了
不过由于状态多两维 而且一开始的写法每次询问都需要重新计算 因而时间比较挫 要$1.4s$
观察后可发现如果较大数的当前位之前于限制条件不等 那么后面的数的选取都是任意的
所以这种情况下并不用每次重新计算 加了这个常数优化后要 $0.6s$
再加上一个对于当前状态贡献一定是$0$的剪枝后还要$0.48s$
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const int N = 1000, mod = 998244353; int f [2][2][2], cnt [2][2][2];//cnt记录的是时间戳 bool bin ; int num[310]; char s[310]; int t, len, n; void init() { n = 0; while(len) { for(int i = len; i; --i) { num[i - 1] += (num[i] & 1) * 10; num[i] >>= 1; } bin[++n] = (num[0] != 0); num[0] = 0; if(!num[len]) --len; } } int dfs(int x, int dif, bool over, bool same, bool top) { if(cnt[x][dif][over][same][top] == t + 1 || (cnt[x][dif][over][same][top] && !top)) return f[x][dif][over][same][top]; cnt[x][dif][over][same][top] = t + 1; if(!x) return f[x][dif][over][same][top] = !over; if(over && dif >= x) return f[x][dif][over][same][top] = 0; int re = 0; if(!top || bin[x]) { re += dfs(x - 1, dif, over, same, top); re += dfs(x - 1, dif + (over ? 1 : -1), over || dif == 1, 0, top); re = (re >= mod ? re - mod : re); } if(!same) { re += dfs(x - 1, abs(dif + (over ? -1 : 1)), over && dif, 0, top && !bin[x]); re = (re >= mod ? re - mod : re); } re += dfs(x - 1, dif, over, same, top && !bin[x]); re = (re >= mod ? re - mod : re); return f[x][dif][over][same][top] = re; } int main() { scanf("%d", &t); while(t--) { scanf("%s", s + 1); len = strlen(s + 1); for(int i = 1; i <= len; ++i) num[i] = s[len - i + 1] - '0'; init(); printf("%d\n", dfs(n, 0, 1, 1, 1)); } return 0; }
想到/理解了 更好的方法再来改改吧
相关文章推荐
- Java HttpSession完成简单购物车功能
- 坐标系之小球向量坐标碰撞
- Mybatis-浅析
- 龙龟的文具盒诞生啦
- 常见的因果案例,希望能解除您心中的疑惑从此深信因果
- iOS GCD使用指南
- 获取手机信息(UIDevice、NSBundle、NSLocale)
- Log4j
- Redis 常见的性能问题和解决方法
- 多行数据合并成一行,cms相关
- 面试 - Android 几个面试题
- java EE解决中文乱码问题
- 创建Bean的方式
- 中年失业后的思考
- hdu1316 How Many Fibs?
- UVA - 1218 Perfect Service(树形dp)
- 如何删除或重置spfile中的参数
- ubuntu12.04_命令
- Android Studio添加本地开源库的方法
- Activity、Service、Task、Process和Thread的关系