hdu4352 XHXJ's LIS(数位Dp)
2016-07-17 17:26
295 查看
题目链接:点这里!!!
题意:叫你求[L,R]区间里数(每位拆开)的最长上升子序列长度为k的数有多少?
数据范围:1<L<=R<2^63-1,1<=k<=9。
题解:数位dp。
设dp[i][j][k]为当前位是第i位,前i+1位最长上升子序列状态为j,最长上升子序列为k的情况。
j状态维护一个最长上升子序列的时候我们预处理出来更新j状态的操作,因为最长才10,2^10*10,并不难。
当然还要注意前缀全部为零的情况!!
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<sstream>
#include<algorithm>
#include<vector>
#include<bitset>
#include<set>
#include<queue>
#include<stack>
#include<map>
#include<cstdlib>
#include<cmath>
#define LL long long
#define pb push_back
#define pa pair<int,int>
#define clr(a,b) memset(a,b,sizeof(a))
#define lson lr<<1,l,mid
#define rson lr<<1|1,mid+1,r
#define bug(x) printf("%d++++++++++++++++++++%d\n",x,x)
#define key_value ch[ch[root][1]][0]
#pragma comment(linker, "/STACK:102400000000,102400000000")
const LL MOD = 1000000007;
const int N = 200+15;
const int maxn = 1e5+15;
const int letter = 130;
const LL INF = 1e7;
const double pi=acos(-1.0);
const double eps=1e-10;
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
LL dp[25][1<<13][13];
int q[25][1<<13][13];
int cnt[1<<13],f[1<<13][13];
int b[25],z;
LL x,y;
int lowbit(int x){return x&(-x);}
int ff(int vs,int s){
for(int i=s;i<10;i++){
if(vs&(1<<i)) return (vs^(1<<i))|1<<s;
}
return vs|1<<s;
}
void init(){
cnt[1]=1;
for(int i=2;i<(1<<10);i++){
int x=i,num=0;
while(x){num++,x-=lowbit(x);}
cnt[i]=num;
}
for(int i=0;i<(1<<10);i++){
for(int j=0;j<10;j++){
f[i][j]=ff(i,j);
}
}
}
LL dfs(int bo,int zer,int i,int j,int k){
if(i==0) return cnt[j]==k;
if(bo&&q[i][j][k]) return dp[i][j][k];
if(bo){
LL &ret=dp[i][j][k];
q[i][j][k]=1;
for(int h=0;h<=9;h++){
ret+=dfs(bo,h==0&&zer,i-1,h==0&&zer?0:f[j][h],k);
}
return ret;
}
else {
LL ret=0;
for(int h=0;h<=b[i];h++){
ret+=dfs(h!=b[i],h==0&&zer,i-1,h==0&&zer?0:f[j][h],k);
}
return ret;
}
}
LL get(LL x,int z){
int k=0;
while(x){b[++k]=(int)(x%10),x/=10;}
return dfs(0,1,k,0,z);
}
int main(){
init();
int T,cas=0;
scanf("%d",&T);
while(T--){
scanf("%I64d%I64d%d",&x,&y,&z);
printf("Case #%d: %I64d\n",++cas,get(y,z)-get(x-1,z));
}
return 0;
}
/*
100
1 10000000000 6
1 10000000000000 6
123 321 2
123 321 2
1 10000000000000 6
1 10000000000 6
*/
题意:叫你求[L,R]区间里数(每位拆开)的最长上升子序列长度为k的数有多少?
数据范围:1<L<=R<2^63-1,1<=k<=9。
题解:数位dp。
设dp[i][j][k]为当前位是第i位,前i+1位最长上升子序列状态为j,最长上升子序列为k的情况。
j状态维护一个最长上升子序列的时候我们预处理出来更新j状态的操作,因为最长才10,2^10*10,并不难。
当然还要注意前缀全部为零的情况!!
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<sstream>
#include<algorithm>
#include<vector>
#include<bitset>
#include<set>
#include<queue>
#include<stack>
#include<map>
#include<cstdlib>
#include<cmath>
#define LL long long
#define pb push_back
#define pa pair<int,int>
#define clr(a,b) memset(a,b,sizeof(a))
#define lson lr<<1,l,mid
#define rson lr<<1|1,mid+1,r
#define bug(x) printf("%d++++++++++++++++++++%d\n",x,x)
#define key_value ch[ch[root][1]][0]
#pragma comment(linker, "/STACK:102400000000,102400000000")
const LL MOD = 1000000007;
const int N = 200+15;
const int maxn = 1e5+15;
const int letter = 130;
const LL INF = 1e7;
const double pi=acos(-1.0);
const double eps=1e-10;
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
LL dp[25][1<<13][13];
int q[25][1<<13][13];
int cnt[1<<13],f[1<<13][13];
int b[25],z;
LL x,y;
int lowbit(int x){return x&(-x);}
int ff(int vs,int s){
for(int i=s;i<10;i++){
if(vs&(1<<i)) return (vs^(1<<i))|1<<s;
}
return vs|1<<s;
}
void init(){
cnt[1]=1;
for(int i=2;i<(1<<10);i++){
int x=i,num=0;
while(x){num++,x-=lowbit(x);}
cnt[i]=num;
}
for(int i=0;i<(1<<10);i++){
for(int j=0;j<10;j++){
f[i][j]=ff(i,j);
}
}
}
LL dfs(int bo,int zer,int i,int j,int k){
if(i==0) return cnt[j]==k;
if(bo&&q[i][j][k]) return dp[i][j][k];
if(bo){
LL &ret=dp[i][j][k];
q[i][j][k]=1;
for(int h=0;h<=9;h++){
ret+=dfs(bo,h==0&&zer,i-1,h==0&&zer?0:f[j][h],k);
}
return ret;
}
else {
LL ret=0;
for(int h=0;h<=b[i];h++){
ret+=dfs(h!=b[i],h==0&&zer,i-1,h==0&&zer?0:f[j][h],k);
}
return ret;
}
}
LL get(LL x,int z){
int k=0;
while(x){b[++k]=(int)(x%10),x/=10;}
return dfs(0,1,k,0,z);
}
int main(){
init();
int T,cas=0;
scanf("%d",&T);
while(T--){
scanf("%I64d%I64d%d",&x,&y,&z);
printf("Case #%d: %I64d\n",++cas,get(y,z)-get(x-1,z));
}
return 0;
}
/*
100
1 10000000000 6
1 10000000000000 6
123 321 2
123 321 2
1 10000000000000 6
1 10000000000 6
*/
相关文章推荐
- Docker安装及镜像管理
- 如何计算两个文档的相似度(一)
- 《linux学习》之怎么安装搜狗输入法
- Linux多线程与同步
- iOS获取经纬度
- Android 自定义View (一)
- 专访腾讯徐汉彬:架构、优化环环相扣,日请求8亿只是起点
- 杭电oj -1008
- ARP协议学习
- 关于《自己动手写CPU》使用GNU工具过程遇到的问题
- memove 的实现
- 用位运算实现四则运算之加减乘除
- Python遇到的小问题与解决方法,时时更新!
- Bit and Byte Order
- 深度解析:清理烂代码
- Python学习笔记(2)—搜索路径
- jenkins2 pipeline 语法快速参考
- 异步编程系列06章 以Task为基础的异步模式(TAP)
- bzoj1018 堵塞的交通traffic(线段树)
- 关于web前端面试题系列之必考面试题(面试官总结)