HDU 5787 K-wolf Number (数位DP)

来源:互联网 发布:子宫肌瘤微创手术知乎 编辑:程序博客网 时间:2024/05/17 01:33

此为转载,原帖:http://blog.csdn.net/chy20142109/article/details/52103601

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5787

题意:求区间[L,R]内,任意相邻k位(如果位数不足k,就是全部的数位)没有两两相同的数位的数的个数。

思路:数位DP,因为K<=5,我们最多需要保存下来当前位的前4位就足够了。
因为dp[pos][p1][p2][p3][p4]表示,现在枚举取第pos位,pos位之前的四位分别为p1,p2,p3,p4,p4是pos的上一位。那么p1~p4的范围就是0~9,但是数是没有前导0的,而且k可能为2,3,4,不需要保存到前4位,所以我们令p = 10来表示这一位不需要保存,也许可能是前导0,也许是不需要保存。

那么dfs函数可以写成 dfs( int pos , int p1 , int p2 , int p3 , int p4 , bool flag ) flag表示pos位能否取到全部的数位(0~9)还是会受到前面最高位的影响只能取一部分。
那么统计下一位的时候就可以分为两种情况:1、pos位之前都取的0,而pos位也取0,一直都是前导零。2、pos位取的i去和p判断一下有没有重复(根据k来判断需要比较几个p),假设这种情况,K = 3,而我们现在正在取第二位,i会和p4和p3去比较一下,但是只有p4是我们取过的值,不过p3此时是10,所以也是可以向下统计的。

#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#include <cstdlib>#include <cctype>#include <string>#include <iostream>#include <vector>#include <map>#include <set>#include <queue>#include <ctime>using namespace std;typedef long long ll;typedef pair<int, int> pii;#define pb push_back#define mp make_pair#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define calm (l+r)>>1const int INF = 2139062143;ll dp[20][11][11][11][11];int digit[20];ll L,R;int K;bool check(int x,int a,int b,int c,int d){//根据K来判断需要和几个数做比较    if(K==2)return x!=a;    if(K==3)return x!=a&&x!=b;    if(K==4)return x!=a&&x!=b&&x!=c;    if(K==5)return x!=a&&x!=b&&x!=c&&x!=d;}ll dfs(int pos,int p1,int p2,int p3,int p4,bool flag){    if(pos==0){//如果p4==10,表示之前全部取了0        return p4!=10;    }    if(!flag&&dp[pos][p1][p2][p3][p4]!=-1)return dp[pos][p1][p2][p3][p4];//如果保存了结果就直接返回    int mx=9;    if(flag)mx=digit[pos];//如果!flag,表示当前位置一定比原来的数小,那么[0,9]都可以取,否则,只能取到当前位置的数    ll ans=0;    for(int i=0;i<=mx;i++){        if(i==0&&p4==10)ans+=dfs(pos-1,10,10,10,10,flag&&i==mx);        else if(check(i,p4,p3,p2,p1)){            ans+=dfs(pos-1,p2,p3,p4,i,flag&&i==mx);        }    }    if(!flag)dp[pos][p1][p2][p3][p4]=ans;    return ans;}ll cal(ll x){    if(x==0)return 0;    int len=0;    while(x){        digit[++len]=x%10;        x/=10;    }    return dfs(len,10,10,10,10,true);}int main(){    //freopen("D://input.txt","r",stdin);    while(scanf("%I64d%I64d%d",&L,&R,&K)!=EOF){        memset(dp,-1,sizeof dp);        printf("%I64d\n",cal(R)-cal(L-1));    }    return 0;}
0 0
原创粉丝点击