hdu6156 Palindrome Function数位dp
来源:互联网 发布:刘姓取名知乎 编辑:程序博客网 时间:2024/05/21 19:46
游戏体验很差,比赛之前没怎么接触过数位dp,然后死坑在这里就是不会,然后比赛结束后,去百度了下数位dp,发现。。。这就是一道模板题啊,模板一套稍微改动就过了;
学数位dp可去http://blog.csdn.net/wust_zzwh/article/details/52100392;
题意:求L~R所有的数的l~r进制的f(x,k进制), 如果x是回文串f(x,k进制) = k, 否则等于1;
枚举进制,求出每一种情况,注意膜k,不是膜10,T_T调了好久才发现错在这;
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <algorithm> #include <string.h> #include <math.h> #include <vector> #include <set> #include <map> #include <queue> #include <stack> using namespace std; typedef long long ll; const int maxn = 100;int a[maxn],k,n;int temp[maxn];ll dp[40][maxn][maxn][2];ll dfs(int pos,bool status,int len,bool limit,int k){ if( pos < 0 ) { if( status ) return k; else return 1; } if(!limit && dp[k][pos][len][status]!=-1) return dp[k][pos][len][status]; int up=limit?a[pos]:k-1; ll ans=0; for(int i=0;i<=up;i++) { temp[pos]=i; if( i == 0 && len == pos) { ans += dfs(pos-1, status, len-1, limit && (i==up),k); } else if( status && pos < (len+1)/2 ) { ans += dfs(pos-1, i == temp[len-pos], len, limit&&(i==up),k ); } else { ans += dfs(pos-1, status, len, limit&&(i==up),k ); } } if(!limit) dp[k][pos][len][status]=ans; return ans; } ll solve(ll x,int k) { if( x == 0 ) return k; int pos=0; while(x) { a[pos++]=x%k; x/=k; } return dfs(pos-1,true,pos-1,true,k);} int main() { ll le,ri,l,r; int t; scanf("%d",&t); int cases=1; memset(dp,-1,sizeof(dp)); while(t--) { ll res=0; scanf("%lld%lld%lld%lld",&le,&ri,&l,&r); for( int i = l; i <= r; i++ ) { res += solve(ri, i) - solve(le-1, i); } printf( "Case #%d: %lld\n", cases++, res ); } }
模板
typedef long long ll; int a[20]; ll dp[20][state];//不同题目状态不同 ll dfs(int pos,/*state变量*/,bool lead/*前导零*/,bool limit/*数位上界变量*/)//不是每个题都要判断前导零 { //递归边界,既然是按位枚举,最低位是0,那么pos==-1说明这个数我枚举完了 if(pos==-1) return 1;/*这里一般返回1,表示你枚举的这个数是合法的,那么这里就需要你在枚举时必须每一位都要满足题目条件,也就是说当前枚举到pos位,一定要保证前面已经枚举的数位是合法的。不过具体题目不同或者写法不同的话不一定要返回1 */ //第二个就是记忆化(在此前可能不同题目还能有一些剪枝) if(!limit && !lead && dp[pos][state]!=-1) return dp[pos][state]; /*常规写法都是在没有限制的条件记忆化,这里与下面记录状态是对应,具体为什么是有条件的记忆化后面会讲*/ int up=limit?a[pos]:9;//根据limit判断枚举的上界up;这个的例子前面用213讲过了 ll ans=0; //开始计数 for(int i=0;i<=up;i++)//枚举,然后把不同情况的个数加到ans就可以了 { if() ... else if()... ans+=dfs(pos-1,/*状态转移*/,lead && i==0,limit && i==a[pos]) //最后两个变量传参都是这样写的 /*这里还算比较灵活,不过做几个题就觉得这里也是套路了 大概就是说,我当前数位枚举的数是i,然后根据题目的约束条件分类讨论 去计算不同情况下的个数,还有要根据state变量来保证i的合法性,比如题目 要求数位上不能有62连续出现,那么就是state就是要保存前一位pre,然后分类, 前一位如果是6那么这意味就不能是2,这里一定要保存枚举的这个数是合法*/ } //计算完,记录状态 if(!limit && !lead) dp[pos][state]=ans; /*这里对应上面的记忆化,在一定条件下时记录,保证一致性,当然如果约束条件不需要考虑lead,这里就是lead就完全不用考虑了*/ return ans; } ll solve(ll x) { int pos=0; while(x)//把数位都分解出来 { a[pos++]=x%10;//个人老是喜欢编号为[0,pos),看不惯的就按自己习惯来,反正注意数位边界就行 x/=10; } return dfs(pos-1/*从最高位开始枚举*/,/*一系列状态 */,true,true);//刚开始最高位都是有限制并且有前导零的,显然比最高位还要高的一位视为0嘛 } int main() { ll le,ri; while(~scanf("%lld%lld",&le,&ri)) { //初始化dp数组为-1,这里还有更加优美的优化,后面讲 printf("%lld\n",solve(ri)-solve(le-1)); } }
阅读全文
0 0
- HDU6156 Palindrome Function[数位DP]
- hdu6156 Palindrome Function数位dp
- hdu6156 Palindrome Function 数位dp
- 【HDU6156】Palindrome Function(数位DP+回文串)
- hdu6156 Palindrome Function (数位dp)
- hdu6156 Palindrome Function CCPC网赛1007 数位dp
- HDU6156-Palindrome Function
- HDU6156-Palindrome Function
- HDU6156 Palindrome Function
- hdu6156 数位dp
- hdu6156-(数位dp)
- HDU6156(数位dp)
- hdu6156 Palindrome Function 思维题
- hdu 6156 Palindrome Function 数位DP
- HDU 6156 Palindrome Function 经典数位DP
- HDU 6156 Palindrome Function 数位DP
- Hdu 6156 Palindrome Function【数位Dp】
- HDU 6156 Palindrome Function(数位DP)
- ORACLE判别字段是否包含中文
- [NOIP模拟赛]排列问题
- 不具参考价值--Mysql设置外键及触发器约束问题
- Android应用组件之片段(Fragment)介绍1
- hihoCoder 1558 H国的身份证号码I(dfs)
- hdu6156 Palindrome Function数位dp
- Pandas 读取txt表格
- java、C#以及C++中&&和||,&和|的联系和区别
- Java中4大基本加密算法解析
- Android应用组件之片段(Fragment)介绍2
- Python基础01 hello word
- Java常见面试题—JVM运行时数据区域
- Java之Properties(配置文件类)
- 业务办理