您的位置:首页 > 其它

hdu-5787-K-wolf Number-数位DP

2016-08-05 22:56 330 查看
http://acm.hdu.edu.cn/showproblem.php?pid=5787

题意:给L,R

求区间内有多少个数,满足 数位里, 每k位都是两两不同的。

数位DP 

dp5[20][a][b][c][d];   第一维是pos,后面四维表示当前pos位置之前的四位分别是什么

转移就是先判断  a,b,c,d,i是否合法,合法则可以转移。

要特殊处理的就是刚开始位数不足k位时,例如 00005,00010这样也是合法的,但是如果填零会炸掉(与真实的零冲突),所以,我们填10,

因为默认保证了遍历到第pos位时,前四个一定是合法的(即两两不同),因此判合法只需要判pos位和前四位都不同即可

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
typedef long long ll;
const long long maxn=11;
long long dp5[20][maxn][maxn][maxn][maxn];
long long aa[20];
long long k;
bool ok(int a,int b,int c,int d,int e)
{
if (k==2) return d!=e;
if (k==3) return d!=e&&e!=c;
if (k==4)return e!=d&&e!=c&&e!=b;
if (k==5)return e!=d&&e!=c&&e!=b&&e!=a;
}

long long dfs(int pos,int a,int b,int c,int d,int flag)
{
long long ans=0;
if (pos==0) return d!=10;
if (!flag && dp5[pos][a][b][c][d]!=-1 )
return dp5[pos][a][b][c][d];
int up;
if (flag) up=aa[pos];
else up=9;
for (int i=0; i<=up; i++)
{
int ff;
if (!flag) ff=0;
else
{
if (i==up) ff=1;
else ff=0;
}
if (!i&&d==10) ans+=dfs(pos-1,10,10,10,10,ff);
else if (ok(a,b,c,d,i))
ans+=dfs(pos-1,b,c,d,i,ff);

}
if (!flag)
dp5[pos][a][b][c][d]=ans;
return ans;

}
long long work(long long x)
{
int len=0;
while(x)
{
aa[++len]=x%10;
x/=10;
}
return dfs(len,10,10,10,10,1);
}
int main()
{
memset(dp5,-1,sizeof dp5);

long long tt,cas=0;
// scanf("%lld",&tt);
long long m;
long long cnt=1;
long long b,a;

while (scanf("%lld%lld",&a,&b)!=EOF)
{
a-- ;
memset(dp5,-1,sizeof dp5);

scanf("%lld",&k);
printf("%lld\n",work(b)-work(a));

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: