poj1351 Number of Locks(数位dp)

题意:某工厂生产一种锁,锁上面有n条槽,现要求生产出来的锁,满足下述条件:

1. 槽深 一定是{1,2,3,4}中的某个值

2. 至少存在 一对相邻的槽,两槽的深度差等于3

3. 至少存在 3种不同深度的槽。

问:已知n,求有多少中排列组合方式满足上述条件

样例:

2:0    因为只有2个槽,不满足条件3;

3:8   3个槽满足的方案有 : 142 、143、 241 、214 、341 、314 、413 、412

解题:数位dp的思想,我们把每个方案 看成一个数字 比如142 就说明 第一个槽深是1,第二个槽深是4......

如果有3个槽,那么满足约束条件的方案 一定落在 111 ~ 444 之间,这样数位dp的范围就有了,

满足条件1,我们只需要在枚举的时候只1~4的范围即可,要满足条件3,在枚举过程中计算种类即可

扫描二维码关注公众号,回复: 2512002 查看本文章

要满足条件2,只要数字中出现连续的 14 或者 41的情况即可。

接下来就是找状态

状态:ll dp[i][j][k][l]; 表示 枚举到第i位,j表示前面有无出现14/41,k表示前一位的数字是k,l表示前面出现了l种数字 的情况数!

找到状态,接下来就容易做了...

#include<stdio.h>
#include<memory.h>
typedef long long ll;
const int maxn = 17;
ll dp[maxn+1][2][5][5];
ll x[maxn+10];

//枚举到pos位,前一位的数字是pre,find表示有无找到14或者41的情况,ff[]标志该数字有无出现过,kind出现了几种数字
ll dfs(int pos,ll pre,bool find,bool ff[5],int kind,bool limit)
{
    if(pos==-1) return (find && kind >=3);
    
    if(!limit && dp[pos][find][pre][kind]!=-1)  return dp[pos][find][pre][kind];
    
    ll up = limit?x[pos]:4;
    ll rs = 0;
    for(ll i=1;i<=up;i++)
    {
        if(ff[i]==false)
        {
            ff[i] = true;
            
            if((pre==1 && i==4) || (pre==4 && i==1))
            {
                rs = rs + dfs(pos-1,i,true,ff,kind+1,limit&&i==up);
            }else{
                rs = rs + dfs(pos-1,i,find,ff,kind+1,limit&&i==up);     
            }
            
            ff[i] = false;
        }else if(ff[i]==true){
            if((pre==1 && i==4) || (pre==4 && i==1))
            {
                rs = rs + dfs(pos-1,i,true,ff,kind,limit&&i==up);
            }else{
                rs = rs + dfs(pos-1,i,find,ff,kind,limit&&i==up);     
            }
        }
    }
    if(!limit) dp[pos][find][pre][kind] = rs;
    return rs;
}
ll solve(ll xx)
{
    int pos = 0;
    while(xx)
    {
        x[pos++] = xx%10;
        xx = xx/10;
    }
    bool ff[5]={false};
    return dfs(pos-1,0,false,ff,0,true);
}
int main()
{
    int n;
    memset(dp,-1,sizeof(dp));
    while(true)
    {
        scanf("%d",&n);
        if(n==-1) break;
        ll a=0,b=0;
        for(int i=1;i<=n;i++)
        {
            a = a*10ll + 1ll;
            b = b*10ll + 4ll;
        }    
//        printf("a == %lld,b==%lld\n",a,b);
        printf("%d: %lld\n",n,solve(b)-solve(a));
    }
    return 0;
}//0ms

努力吧,渣科

猜你喜欢

转载自blog.csdn.net/zark721/article/details/81154290