您的位置:首页 > 其它

HDU 4352 XHXJ's LIS【数位DP】

2016-11-05 15:42 309 查看
题目:点击打开链接

题意:求出给定区间内有多少数的最长严格单调子序列长度等于k

分析:因为这是严格递增的,所以长度不会大于9,考虑用二进制状压保存当前情况下的LIS,令dp[pos][num][K],num表示当前情况下按位保存0~9的出现情况(num<(1<<10)),对应位置出现该数存为1,未出现则为0,若当前数为1253,则num=0000101110,考虑到用复杂度为nlogn的LIS的思想,若对于当前的数,存在非末尾的某个数位大于等于最末尾的数位,则要把num的该数位改为0,把末尾数位的数的对应数位改为1,即上例中1253中5>3,则原来值125的num=0000100110要改为0000001110而不是0000101110。若不存在非末尾的某个数位大于等于最末尾的数位,则直接把末尾数位的数的对应数位改为1。这样就保证了每次取的都是最小的值,再统计num中有多少个1,也就能求出最长的长度了。注意排除前缀零的影响。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <stdio.h>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <set>
#include <vector>
#include <map>
#define sqr(x) ((x)*(x))
#define PR pair<int,int>
#define MP make_pair
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ll long long
const ll INF = 1e18;
const int inf=0x3f3f3f3f;
const int M=100010;
const int N=15;
const ll MOD=1000000007;
const double eps=1e-8;
const double pi=acos(-1.0);
using namespace std;
int dig[20],K;
ll dp[20][1<<10][11],l,r;
int getsta(int x,int s)
{
for(int i=x;i<10;i++)
if(s&(1<<i)) return (s^(1<<i))|(1<<x);
return s|(1<<x);
}
int getlis(int x)
{
int ans=0;
while(x)
{
if(x&1) ans++;
x>>=1;
}
return ans;
}
ll dfs(int pos,int num,int lim,int first)
{
if(pos==0) return getlis(num)==K;
if(!lim&&dp[pos][num][K]!=-1) return dp[pos][num][K];
int upper=lim?dig[pos]:9;
ll res=0;
for(int i=0;i<=upper;i++)
{
if(i==0&&first) res+=dfs(pos-1,0,lim&&(i==upper),1);
else res+=dfs(pos-1,getsta(i,num),lim&&(i==upper),0);
}
if(!lim) dp[pos][num][K]=res;
return res;
}
ll calc(ll x)
{
int len=0;
while(x)
{
dig[++len]=x%10;
x/=10;
}
return dfs(len,0,1,1);
}
int main()
{
memset(dp,-1,sizeof(dp));
int T;
scanf("%d",&T);
for(int cas=1;cas<=T;cas++)
{
scanf("%I64d%I64d%d",&l,&r,&K);
printf("Case #%d: %I64d\n",cas,calc(r)-calc(l-1));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: