码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2017-12-13 23:40:15      阅读:107      评论:0      收藏:0      [点我收藏+]

标签:操作   图片   bsp   lld   枚举   gif   show   memset   long   

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

  显然用一个单调栈就可以完成:塞入栈中,将比它大的所有数都弹出,如果栈中没有当前数,答案+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)

标签:操作   图片   bsp   lld   枚举   gif   show   memset   long   

原文地址:http://www.cnblogs.com/Sakits/p/8034800.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!