您的位置:首页 > 其它

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
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: