HDU 4352 XHXJ's LIS (数位DP,状压)
2015-10-05 15:11
253 查看
题意:
前面3/4的英文都是废话。将一个正整数看成字符串,给定一个k,问区间[L,R]中严格的LIS=k的数有多少个?
思路:
实在没有想到字符0~9最多才10种,况且也符合O(nlogn)求LIS的特点,所以用状态压缩可以解决。
看到状态压缩的字眼基本就会做了,增加一维来保存当前LIS的状态。由于求LIS时的辅助数组d[i]表示长度为i的LIS最后一个元素,d数组是严格递增的,所以好好利用d数组的特性来设计状态压缩才是关键。压缩的状态0101可以表示:仅有0和2在数组d中,即d[1]=0,d[2]=2的意思。状态的设计方法有多种。
此题在考虑前导零问题时,逐个枚举位数,可以这样做是因为如果位数超过了1,则最后一个数位若为0是不会对结果构成影响的,因为最后的0都不会被考虑在LIS中。而对于那些个位数为0(或者说后缀0)会对结果产生影响的,最好是不要这样用了(例如spoj Balanced Numbers就不可以)。
AC代码
前面3/4的英文都是废话。将一个正整数看成字符串,给定一个k,问区间[L,R]中严格的LIS=k的数有多少个?
思路:
实在没有想到字符0~9最多才10种,况且也符合O(nlogn)求LIS的特点,所以用状态压缩可以解决。
看到状态压缩的字眼基本就会做了,增加一维来保存当前LIS的状态。由于求LIS时的辅助数组d[i]表示长度为i的LIS最后一个元素,d数组是严格递增的,所以好好利用d数组的特性来设计状态压缩才是关键。压缩的状态0101可以表示:仅有0和2在数组d中,即d[1]=0,d[2]=2的意思。状态的设计方法有多种。
此题在考虑前导零问题时,逐个枚举位数,可以这样做是因为如果位数超过了1,则最后一个数位若为0是不会对结果构成影响的,因为最后的0都不会被考虑在LIS中。而对于那些个位数为0(或者说后缀0)会对结果产生影响的,最好是不要这样用了(例如spoj Balanced Numbers就不可以)。
#include <bits/stdc++.h> #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <map> #include <algorithm> #include <vector> #include <iostream> #define pii pair<int,int> #define INF 0x7f3f3f3f #define LL long long #define ULL unsigned long long using namespace std; const double PI = acos(-1.0); const int N=20; LL f [1<<11][11], bit ; //[位数][状态][k] int insert(int s,bool flag,int pos) //修改状态 { for(int i=pos; i<=9&&flag; i++) //找到第一位>=pos的,抹去 if(s&(1<<i)) { s^=(1<<i); break; } return s|(1<<pos); } int gethigh(int s) //获取LIS最大元素,即d[len]。 { for(int i=9; i>=0; i--) if(s&(1<<i)) return i; return -1; } LL dfs(int i,int up,int s,int k,bool e) { //up为总位数,s为状态,k为仍需一段len=k的串来组成LIS=K的 if(i==0) return k==0; if(i<k) return 0; //剩下的位数已不够k个,不能组成LIS=k if(!e && ~f[i][s][k] ) return f[i][s][k]; LL ans=0; int d= i==up? 1: 0; //为了解决前缀0的情况,起始不为0 int u= e? bit[i]: 9; int h=gethigh(s); //LIS的最大元素 for( ; d<=u; d++) { if(d>h) ans+=dfs(i-1,up,insert(s,0,d),k-1,e&&d==u); else ans+=dfs(i-1,up,insert(s,1,d),k,e&&d==u); //LIS长度不变 } return e? ans: f[i][s][k]=ans; } LL cal(LL n,int k) { if(n==0) return 0; int len=0; while(n) //拆数 { bit[++len]=n%10; n/=10; } LL ans=0; for(int i=k; i<len; i++) //为了解决前导0问题,逐个枚举 ans+=dfs(i,i,0,k,false); if(len>=k) ans+=dfs(len,len,0,k,true); return ans; } int main() { //freopen("input.txt","r",stdin); memset(f, -1, sizeof(f)); LL L, R;int t, K, Case=0; cin>>t; while( t-- ) { scanf("%lld%lld%d",&L,&R,&K); printf("Case #%d: %lld\n", ++Case, cal(R,K)-cal(L-1,K)); } return 0; }
AC代码
相关文章推荐
- 自定义PopupWindow的实现
- Binder进程间通信机制的Service Manager代理对象获取过程
- QT5 学习之路20---标准对话框 QMessageBox
- HDU-5122-K.Bro Sorting
- 2048游戏C语言代码
- myeclipse 删除不再使用的工作空间记录
- 线程缓存的探索
- clr 元数据
- matlab for循环的三种类型
- H-Index II -- leetcode
- android 模拟器命令 附:模拟器不能联网设置
- tingda.git上传SAE
- C++类构造函数初始化列表
- 时尚起义开源话题微博系统 v.0.4.5 上传漏洞
- AspNetPager常用属性及一些样式(本文摘自网络,作者:x123jing)
- yum用法第二篇-自定义创建yum仓库
- UVA_540: Team Queue
- Python - Merge Sort
- html编码
- LINGO的集循环函数