zoukankan      html  css  js  c++  java
  • 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
    ", solve(r)-solve(l-1));
    }
    View Code
  • 相关阅读:
    ARM处理器
    进程和线程通俗理解
    const与指针
    字符提取命令
    ThinkPHP之视图模版的使用
    ThinkPHP之MVC与URL访问
    ThinkPHP之项目搭建
    android之文件存储和读取
    cryptdb中wrapper.lua的分析
    cryptDB安装分析
  • 原文地址:https://www.cnblogs.com/Sakits/p/8034800.html
Copyright © 2011-2022 走看看