51nod 1623 完美消除(数位DP)

Posted Sakits

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51nod 1623 完美消除(数位DP)相关的知识,希望对你有一定的参考价值。

  首先考虑一下给一个数如何求它需要多少次操作。

  显然用一个单调栈就可以完成:塞入栈中,将比它大的所有数都弹出,如果栈中没有当前数,答案+1。

  因为数的范围只有0~9,所以我们可以用一个二进制数来模拟这个栈,并塞到DP的状态里。

  设$dp[i][j][k]$表示前i位数,已经进行了j次操作,栈的状态为k的方案数。

  每次枚举一个数的时候,先把比这个数大的数在状态中都清零,再看看状态中有没有这个数,没有的话答案+1。

  注意需要把状态初始值设为0在栈中...T T

技术分享图片
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#define ll long long
using namespace std;
ll l, r, K;
ll dp[20][20][1<<10];
int a[20];
ll dfs(int pos, int k, int st, bool limit)
{
    if(!pos) return k==K;
    if(!limit && dp[pos][k][st]!=-1) return dp[pos][k][st];
    int up=limit?a[pos]:9; ll ans=0;
    for(int i=0;i<=up;i++)
    {
        int now=st;
        for(int j=i+1;j<=9;j++) now^=((now & (1<<j))!=0)<<j;
        if(st&(1<<i)) ans+=dfs(pos-1, k, now, limit && i==up);
        else if(k<K) ans+=dfs(pos-1, k+1, now|(1<<i), limit && i==up);
    }
    if(!limit) dp[pos][k][st]=ans;
    return ans;
}
ll solve(ll x)
{
    int pos=0;
    while(x) a[++pos]=x%10, x/=10;
    return dfs(pos, 0, 1, 1);
}
int main()
{
    memset(dp, -1, sizeof(dp));
    scanf("%lld%lld%lld", &l, &r, &K);
    printf("%lld\n", solve(r)-solve(l-1));
}
View Code

 

以上是关于51nod 1623 完美消除(数位DP)的主要内容,如果未能解决你的问题,请参考以下文章

51nod 1232 完美数 数位dp

51Nod 1042 数字0-9的数量(数位DP)

51nod 1232 完美数

51nod1043(数位dp)

51nod 1043 幸运号码(数位dp)

[51NOD1230]幸运数(数位DP)