51 nod 1623 完美消除(单调栈+数位DP)

来源:互联网 发布:魔兽世界解锁飞行淘宝 编辑:程序博客网 时间:2024/05/23 01:14

1623 完美消除
基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题
 收藏
 关注

定义数的消除操作为选定[L,R,x],如果数的第L到第R位上的数字都大于等于x,并且这些数都相等,那么该操作是合法的(从低位到高位编号,个位是第一位,百位是第二位……),然后将这些位数上的数减x;否则就是不合法的,不能进行操作。对一个数操作最少的次数使得这个数变成0,这个操作次数称为该数的最小操作数。如:1232的最小操作数为3,一个合法解是[2,2,1],[1,3,2],[4,4,1]。

求L~R中最小操作数为k的数的个数。


例如:132,需要操作3次才能变为0。而131131 => 111131 => 111111 =>0

Input
单组测试数据。三个整数L、R和k(1<=L<=R<=10^18,1<=k<=18)。
Output
一个整数表示答案。
Input示例
10 21 2
Output示例
9

主要没有分析出怎么求一个数的消除次数 其实就是个单调栈

值大的数可以和值小的数一起消除,所以维护一个递增的单调栈即可

因为只有10个数 所以我们可以状压表示状态 当需要消除数时 直接更改状态即可

#include<iostream>#include<algorithm>#include<cstdio>#include<cstdlib>#include<cstring>#include<vector>#include<map>#include <bits/stdc++.h>using namespace std;const int N = 300000+10;typedef  long long LL;const LL mod = 998244353;LL dp[19][1050][19];int k;int pos[20];int cal(int state,int x){    for(int i=x+1;i<=9;i++)        if(state&(1<<i)) state^=(1<<i);    return state;}LL dfs(int len,int state,int limit,int num){    if(len==0) return num==k;    if(!limit&&dp[len][state][num]!=-1) return dp[len][state][num];    int m=limit?pos[len]:9;    LL ans=0;    for(int i=0;i<=m;i++)    {        if((state&(1<<i))||i==0) ans+=dfs(len-1,cal(state|(1<<i),i),limit&&i==m,num);        else ans+=dfs(len-1,cal(state|(1<<i),i),limit&&i==m,num+1);    }    if(!limit) dp[len][state][num]=ans;    return ans;}LL solve(LL x){    int num=0;    while(x)    {        pos[++num]=x%10;        x/=10;    }    return dfs(num,0,1,0);}int main(){    memset(dp,-1,sizeof(dp));    LL l, r;    scanf("%lld %lld %d", &l, &r, &k);    printf("%lld\n",solve(r)-solve(l-1));    return 0;}







原创粉丝点击