您的位置:首页 > 其它

HDU 4352 XHXJ's LIS(数位dp)

2017-04-24 21:32 706 查看
题意:寻找 [L,R] 中满足条件的数的数量。条件:把一个数看成字符串,它的LIS若等于k,则满足条件。

题解:数位dp。

一开始的想法:考虑nlogn的LIS写法,因此状态包含一个长度为10的字符串,由0~9,inf组成。

但是需要把字符串映射成int,用到map,复杂度据说太高了。

正解:nlogn的LIS写法是维护了一个数组,由0~9,inf组成。那么对于本题,我们只要用一个二进制维护出现的数字即可。

#include<cstdio>
#include<string>
#include<map>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;

int k;
ll l,r;
int dig[20];
ll d[20][1024][11];

int nxtsta(int sta,int x) {
for(int i=x;i<=9;++i) {
if((sta>>i)&1) return (sta^(1<<i))|(1<<x);
}
return sta|(1<<x);
}

ll dp(int po,int sta,bool zero,bool limit) {
if(po==-1) {
int cnt=0;
while(sta) {
if(sta&1) ++cnt;
sta>>=1;
}
return cnt==k;
}
if(!zero&&!limit&&d[po][sta][k]!=-1) return d[po][sta][k];

int to=limit?dig[po]:9;
ll ans=0;

for(int i=0;i<=to;++i) {
ans=ans+dp(po-1,(zero&&i==0)?0:nxtsta(sta,i),zero&&i==0,limit&&i==to);
}

if(!zero&&!limit) d[po][sta][k]=ans;
return ans;

}

ll solve(ll x) {
int pos=0;
while(x) {
dig[pos++]=x%10;
x/=10;
}
return dp(pos-1,0,1,1);
}

int main() {
///init
memset(d,-1,sizeof(d));

int T;scanf("%d",&T);
int ca=0;
while(T--) {
printf("Case #%d: ",++ca);

///read
scanf("%lld%lld%d",&l,&r,&k);

///solve
printf("%lld\n",solve(r)-solve(l-1));
}
return 0;
}

//下面代码把自己一开始的想法贴出来,因为我感觉可能是我写丑了...不一定是复杂度的问题

#include<cstdio>
#include<string>
#include<map>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;

string s[2000];
map<string,int> id;
ll l,r;
int k,cnts;
int dig[25];
ll d[25][15][2000];

ll dp(int po,int ids,bool zero,bool limit) {
// cout<<po<<" "<<str<<" "<<endl;
string str=s[ids];
if(po==-1) return (k==10||str[k]=='A')&&str[k-1]!='A';
if(!zero&&!limit&&d[po][k][id[str]]!=-1) return d[po][k][id[str]];

int to=limit?dig[po]:9;
ll ans=0;

for(int i=0;i<=to;++i) {
string tmp=str;
for(int j=0;j<=9;++j) {
if(str[j]>='0'+i) {
if(!(zero&&i==0)) tmp[j]='0'+i;
break;
}
}
if(tmp[k]!='A') continue;
ans=ans+dp(po-1,id[tmp],zero&&i==0,limit&&i==to);
}

if(!zero&&!limit) d[po][k][id[str]]=ans;
return ans;

}

ll solve(ll x) {
int pos=0;
while(x) {
dig[pos++]=x%10;
x/=10;
}
return dp(pos-1,1024,1,1);
}

void dfs(int po,int pre,string str) {
if(po==10) {
int len=str.length();
for(int i=len;i<=9;++i) str=str+'A';
s[++cnts]=str;
id[str]=cnts;
return ;
}

for(int i=pre+1;i<=9;++i) {
char c='0'+i;
dfs(po+1,i,str+c);
}
dfs(10,0,str);
}

int main() {
///init
memset(d,-1,sizeof(d));

///
cnts=0;
dfs(0,-1,"");

int T;scanf("%d",&T);
int ca=0;
while(T--) {
printf("Case #%d: ",++ca);
///read
scanf("%lld%lld%d",&l,&r,&k);

///solve
printf("%lld\n",solve(r)-solve(l-1));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: