zoukankan      html  css  js  c++  java
  • UESTC 884 方老师的专题讲座 --数位DP

    定义:cnt[L][K]表示长度为L,最高位为K的满足条件C的个数。

    首先预处理出cnt数组,枚举当前长度最高位和小一个长度的最高位,如果相差大于2则前一个加上后一个的方法数。

    然后给定n,计算[1,n-1]中满足条件C的数的个数。

    设有K位数,则不足K位的累加,然后枚举K位数的情况,从高位到低位枚举,每次枚举到比该位小1的数,注意:如果某时刻该数中有两位相差大于2,则再枚举下去已经没有意义,因为以后的数再也不会满足条件C,这时退出即可。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <string>
    #define Mod 1000000007
    #define ll long long
    using namespace std;
    #define N 100007
    
    ll cnt[22][12];  //cnt[L][K]:长度为L,最高位为K的满足条件C的数的个数
    ll NUM[21];
    
    ll DP(ll a)    //[1,n-1]
    {
        int i,j,K;
        int pre,head;
        ll res = 0;
        K = 0;
        while(K <= 18 && NUM[K] <= a)
            K++;
        K--;
        //cout<<"K is "<<K<<endl;
        for(i=1;i<K;i++)     //所有小于a长度的长度
            for(j=1;j<=9;j++)   //所有首位
                res += cnt[i][j];
        head = a/NUM[K];      //数a的首位
        for(i=1;i<head;i++)    //从1开始(不含前导0)
            res += cnt[K][i];
        a %= NUM[K];   //去除首位
        pre = head;    //多一位的首位
        for(i=K-1;i>=1;i--)  //长度逐次递减,高位到低位
        {
            head = a/NUM[i];
            for(j=0;j<head;j++)   //小于a的当前位的数做首位
                if(abs(pre-j) >= 2)
                    res += cnt[i][j];
            if(abs(head-pre) < 2)   //如果前面某两位出现差小于2,再枚举后面的数就没意义了,因为无论如何都不会满足了。
                break;
            pre = head;
            a %= NUM[i];  //一个一个去除
        }
        return res;
    }
    
    int main()
    {
        int i,j,l,k;
        ll a,b;
        j = 0;
        NUM[j++] = 0LL;
        for(i=1;i<=19;i++)
            NUM[j++] = (ll)pow(10,i-1);
        //for(i=0;i<j;i++)
            //cout<<NUM[i]<<" ";
        //cout<<endl;
        memset(cnt,0,sizeof(cnt));
        for(k=0;k<=9;k++)
            cnt[1][k] = 1;
        for(l=2;l<=18;l++)
        {
            for(i=0;i<=9;i++)   //长度为l时的首位
            {
                for(k=0;k<=9;k++)   //长度为l-1时的首位
                {
                    if(abs(k-i) >= 2)
                        cnt[l][i] += cnt[l-1][k];
                }
            }
        }
        for(k=0;k<=9;k++)  //10^18
            if(abs(1-k) >= 2)
                cnt[19][1] += cnt[18][k];
    
        while(scanf("%lld%lld",&a,&b)!=EOF)
        {
            printf("%lld
    ",DP(b+1)-DP(a));
        }
        return 0;
    }
    View Code
  • 相关阅读:
    LeetCode 42. Trapping Rain Water
    LeetCode 209. Minimum Size Subarray Sum
    LeetCode 50. Pow(x, n)
    LeetCode 80. Remove Duplicates from Sorted Array II
    Window10 激活
    Premiere 关键帧缩放
    AE 「酷酷的藤」特效字幕制作方法
    51Talk第一天 培训系列1
    Premiere 视频转场
    Premiere 暴徒生活Thug Life
  • 原文地址:https://www.cnblogs.com/whatbeg/p/3762744.html
Copyright © 2011-2022 走看看