zoukankan      html  css  js  c++  java
  • 51NOD 1623 完美消除 数位DP

    题目描述:

      定义数的消除操作为选定[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

    输入:

      单组测试数据。三个整数L、R和k(1<=L<=R<=10^18,1<=k<=18)

    题解:

      典型数位DP

      设定dp[i][j][k] 前i位下所用数字状态j花费次数时k的个数

      注意这里的状态j是指 后面的放入数字能有重复效应的 状态

      例如 313 花费的次数是3 但131花费次数2    两者在第二位的状态 是(3)和(1)

      最后还要注意0不花费

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int N = 30, M = 2e6+10, inf = 2e9, mod = 1e9+7;
    int d[N];
    long long L,R,k,dp[20][1<<10][20],vis[20][1<<10][20];
    int cal(int p,int i) {
        for(int k=i+1;k<=9;k++) if(p&(1<<k)) p^=(1<<k);
        return p;
    }
    long long dfs(int dep,int f,int p,int K)
    {
        if(dep<0) return K==k;
        if(f&&vis[dep][p][K]) return dp[dep][p][K];
        if(f){
            long long& ret = dp[dep][p][K];
            vis[dep][p][K]=1;
            for(int i=0;i<=9;i++)
            {
                if(p&(1<<i)||i==0) {
                    ret+=dfs(dep-1,f,cal(p,i),K);
                }
                else ret+=dfs(dep-1,f,cal(p|(1<<i),i),K+1);
            }
            return ret;
        }
        else {
            long long ret = 0;
            for(int i=0;i<=d[dep];i++)
            {
                if(p&(1<<i)||i==0)
                ret+=dfs(dep-1,i<d[dep],cal(p,i),K);
                else ret+=dfs(dep-1,i<d[dep],cal(p|(1<<i),i),K+1);
            }
            return ret;
        }
    }
    long long solve(long long x)
    {
        memset(dp,0,sizeof(dp));
        memset(vis,0,sizeof(vis));
        int len = 0;
        while(x){
            d[len++] = x%10;
            x/=10;
        }
        dfs(len-1,0,0,0);
    }
    int main(){
     while(scanf("%lld%lld%lld",&L,&R,&k)!=EOF)
       {
            printf("%lld
    ",solve(R)-solve(L-1));
       }
        return 0;
    }
  • 相关阅读:
    已知用经纬度表示的两点,求两点之间的直线距离
    linux 管道--转
    Five ways to maximize Java NIO and NIO.2--reference
    java获取当前方法
    事务策略: 了解事务陷阱--转
    实例详解 EJB 中的六大事务传播属性--转
    全面分析 Spring 的编程式事务管理及声明式事务管理--转
    Spring 事务管理高级应用难点剖析--转
    Java NIO——Selector机制源码分析---转
    Java NIO类库Selector机制解析--转
  • 原文地址:https://www.cnblogs.com/zxhl/p/5658443.html
Copyright © 2011-2022 走看看