数位统计练习

论文:

http://hi.baidu.com/3xianbin/item/917aca907a3fb6f4291647fc

http://wenku.baidu.com/view/d2414ffe04a1b0717fd5dda8.html

其中一道题目求给定区间的所有数的k进制的各位数字的和:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll __int64
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d
", x)
#define lowbit(x)   (x)&(-x)
#define Read()  freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 137
#define N 207

using namespace std;


const int inf = 0x7f7f7f7f;
const int mod = 1000000007;

ll x,y,n,k;
ll getsum(ll pre,ll n,ll k)
{
    ll C = pre, B = 1;

    for (int i = 0; i < n; ++i)
    {
        B *= k; C *= k;
    }
    B = B*n*(k - 1)/2;
    return B + C;
}
ll dfs(ll pre,ll n,ll k)
{
    ll res = 0;
    if (n < k)
    {
        for (int i = 0; i <= n; ++i)
        {
            res += pre + i;
        }
        return res;
    }

    int d = 0;
    ll t = 1;
    ll tn = n;
    while (tn >= k)
    {
        tn /= k;
        t *= k;
        d++;
    }
    for (int i = 0; i < tn; ++i)
    {
        res += getsum(pre + i,d,k);
    }
    res += dfs(pre + tn,n - tn*t,k);
    return res;
}
int main()
{
    while (cin>>x>>y>>k)
    {
        ll sum1 = dfs(0,y,k);
        ll sum2 = dfs(0,x - 1,k);
        cout<<sum1<<" "<<sum2<<" "<<sum1 - sum2<<endl;
    }
    return 0;
}
View Code

首先贴一下数位DP的简单的模板:

记忆化搜索写的代码,很优雅,美观orz大神们..

转载别人的

int dfs(int i, int s, bool e) {
    if (i==-1) return s==target_s;
    if (!e && ~f[i][s]) return f[i][s];
    int res = 0;
    int u = e?num[i]:9;
    for (int d = first?1:0; d <= u; ++d)
        res += dfs(i-1, new_s(s, d), e&&d==u);
    return e?res:f[i][s]=res;
}

 

其中:

f为记忆化数组;

i为当前处理串的第i位(权重表示法,也即后面剩下i+1位待填数);

s为之前数字的状态(如果要求后面的数满足什么状态,也可以再记一个目标状态t之类,for的时候枚举下t);

e表示之前的数是否是上界的前缀(即后面的数能否任意填)。

for循环枚举数字时,要注意是否能枚举0,以及0对于状态的影响,有的题目前导0和中间的0是等价的,但有的不是,对于后者可以在dfs时再加一个状态变量z,表示前面是否全部是前导0,也可以看是否是首位,然后外面统计时候枚举一下位数。It depends.

于是关键就在怎么设计状态。当然做多了之后状态一眼就可以瞄出来。

注意:

不满足区间减法性质的话(如hdu 4376),不能用solve(r)-solve(l-1),状态设计会更加诡异

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

首先给出一个模板类的题目:

hdu Bomb

题意: 

求小于等于n的包含“49”的数的个数

思路:

数位dp,模板

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val) memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d
", x)
#define lowbit(x)   (x)&(-x)
#define Read()  freopen("data.in", "r", stdin)
#define Write() freopen("d.out", "w", stdout)
#define ll __int64


#define M 100007
#define N 100007

using namespace std;

const int inf = 0x7f7f7f7f;
const int mod = 1000000007;


ll dp[30][10][2];
int bit[30];
ll n;

//pos 表示枚举到的位置,pre表示以pre为前缀,flag表示是否含有49,limit表示当前位置是否受限
ll dfs(int pos,int pre,int flag,int limit)
{
    if (pos == -1) return flag;
    if (!limit && dp[pos][pre][flag] != -1) return dp[pos][pre][flag];

    ll ans = 0;
    int up = limit? bit[pos]:9;
    for (int i = 0; i <= up; ++i)
    {
        int tflag = flag;
        if (pre == 4 && i == 9) tflag = 1;
        int tpre = i;
        ans += dfs(pos - 1,tpre,tflag,(limit && i == up));
    }
    if (!limit) dp[pos][pre][flag] = ans;
    return ans;
}

ll solve(ll n)
{
    int pos = 0;
    while (n)
    {
        bit[pos++] = n%10;
        n /= 10;
    }
    return dfs(pos - 1,0,0,1);
}
int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        CL(dp,-1);
        scanf("%I64d",&n);
        printf("%I64d
",solve(n));
    }
    return 0;
}
View Code

SDUT A-Number and B-Number

题解:http://www.cnblogs.com/E-star/p/3143237.html

CF Codeforces Beta Round #51 D. Beautiful numbers

题意:

求给定区间内[l,r]的数满足被他自身所有非0数整除的数的个数

思路:
转载:

 一个数字要被它的所有非零位整除,即被他们的LCM整除,可以存已有数字的Mask,但更好的方法是存它们的LCM{digit[i]}
    int MOD = LCM{1,2,9} = 5 * 7 * 8 * 9 = 2520
    按照定义,数字x为Beautiful : 
    x % LCM{digit[xi]} = 0
    即 x % MOD % LCM{digit[xi]} = 0
    所以可以只需存x % MOD,范围缩小了
    而在逐位统计时,假设到了pre***(pre指前面的一段已知的数字,而*是任意变)
        ( preSum * 10^pos + next )  % MOD % LCM(preLcm , nextLcm)
    =  ( preSum * 10 ^ pos % MOD + next % MOD ) % LCM(preLcm , nextLcm)
    == 0
    而next,nextLcm是变量,上面的比较式的意义就是
    在已知pos , preSum , preLcm情况下有多少种(next,nextLcm)满足式子为0
    而这个就是一个重复子问题所在的地方了,需要记录下来,用记忆化搜索
    dfs(pos , preSum , preLcm , doing)
    加一个标记为doing表示目前是在计算给定数字的上限,还是没有上限,即***类型的
    这样就将初始化以及逐位统计写在一个dfs了,好神奇!!!
    
    还有一点,10以内的数字情况为2^3 , 3^2 , 5 , 7
    所以最小公倍数组合的情况只有4*3*2*2 = 48

    (我理解的最小公倍数的组和其实就2520的因子的个数)
    可以存起来,我看NotOnlySuccess的写法是
    for(int i = 1 ; i <= MOD ; i ++)
    {
        if(MOD % i == 0)
            index[i] = num++;
    }
    很棒!!

    所以复杂度大概为19*2520*48*10(状态数*决策数)

    我觉得这题状态的设计不能跟具体数字分开,否则会很难设计吧
    所以用记忆化搜索,存起来
    用具体数字去计算,重复的子问题跟pre关系比较密切
    有一个比较重要的切入点就是LCM,还有%MOD缩小范围,才能存储

    还有优化到只需%252的,更快
    不过我觉得%2520比较好理解

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll __int64
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d
", x)
#define lowbit(x)   (x)&(-x)
#define Read()  freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 137
#define N 27

using namespace std;


const int inf = 0x7f7f7f7f;
const int mod = 1000000007;

const int MOD = 2520;
int bit[N];

ll dp[N][2527][50];
int idx[2527];

void init()
{
    int num = 0;
    for (int i = 1; i <= 2520; ++i)
    {
        if (MOD % i == 0)
        {
            idx[i] = num++;
        }
    }
}
int gcd(int a,int b)
{
    if (b == 0) return a;
    return gcd(b,a%b);
}
int LCM(int a,int b)
{
    return (a*b)/gcd(a,b);
}

ll dfs(int pos,int pre,int lcm,int limit)
{
    if (pos == -1) return pre%lcm == 0;

    if (!limit && dp[pos][pre][idx[lcm]] != -1) return dp[pos][pre][idx[lcm]];

    int end = limit? bit[pos]:9;
    ll ans = 0;
    for (int i = 0; i <= end; ++i)
    {
        int tpr = (pre*10 + i)%MOD;
        int tlcm = lcm;
        if (i) tlcm = LCM(tlcm,i);

        ans += dfs(pos - 1,tpr,tlcm,(limit && i == end));
    }
    if (!limit) dp[pos][pre][idx[lcm]] = ans;

    return ans;
}
ll solve(ll n)
{
    int pos = 0;
    while (n)
    {
        bit[pos++] = n%10;
        n /= 10;
    }
    return dfs(pos - 1,0,1,1);
}
int main()
{
    int T;
    ll l,r;
    CL(dp,-1);
    init();
    cin>>T;
    while (T--)
    {
        cin>>l>>r;
        cout<<solve(r) - solve(l - 1)<<endl;
    }
    return 0;
}
View Code

 hdu 352 B-number

题意:

求[1,n]内满足包含13并且能被13整除的数的个数。

思路:

典型的数位统计,只不过自己在设计状态的时候没有考虑完全才开始设计成dp[pos][pres][flag]了,结果输出总是偏多,肯定是限制考虑不全全面了,首先假设我们枚举的到了第二位

31*** 和 22*** 可能后边会存在3这样的话pos = 2 pres =  4,flag = 0 是的情况就不同了,所以我们要记录一下前一个数是什么才能保证数据的正确性。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll __int64
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d
", x)
#define lowbit(x)   (x)&(-x)
#define Read()  freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 137
#define N 27

using namespace std;


const int inf = 0x7f7f7f7f;
const int mod = 1000000007;

int bit[N];
ll dp[N][12][15][2];
ll n;

ll dfs(int pos,int pren,int pres,int flag,int limit)
{
    if (pos == -1) return (pres%13 == 0 && flag);

    if (!limit && dp[pos][pren][pres][flag] != -1) return dp[pos][pren][pres][flag];

    int end = limit? bit[pos]:9;
    ll ans = 0;
    for (int i = 0; i <= end; ++i)
    {
        int tpres = (pres*10 + i)%13;
        int tflag = flag;
        if (pren == 1 && i == 3) tflag = 1;
        ans += dfs(pos - 1,i,tpres,tflag,(limit && i == end));
    }
    if (!limit) dp[pos][pren][pres][flag] = ans;
    return ans;
}
ll solve(ll n)
{
    int pos = 0;
    while (n)
    {
        bit[pos++] = n%10;
        n /= 10;
    }
    return dfs(pos - 1,0,0,0,1);
}
int main()
{
//    Read();
    CL(dp,-1);
    while (~scanf("%I64d",&n))
    {
        cout<<solve(n)<<endl;
    }
    return 0;
}
View Code

 zoj 3416 Balanced Number

题意:
给定一个区间求该区间[L,R]内平衡数的个数,平衡数的定义:4139  存在一个数3  4*2 + 1*1 = 9*1 

思路:
若某一个数是平衡数,那么它的中心是唯一确定的,我们只要设计好状态,然后枚举中间,在进行数位同,在中心轴确定的情况下该区间的数量然后求和即可。

dp[pos][d][pre]  d表示中心的位置。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll long long
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d
", x)
#define lowbit(x)   (x)&(-x)
#define Read()  freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 137
#define N 27

using namespace std;


const int inf = 0x7f7f7f7f;
const int mod = 1000000007;

int bit[25];
ll dp[20][20][2000];

ll dfs(int pos,int d,int pre,int limit)
{
    if (pos == -1) return pre == 0;
    if (!limit && dp[pos][d][pre] != -1) return dp[pos][d][pre];

    ll ans = 0;
    int end = limit? bit[pos] : 9;
    for (int i = 0; i <= end; ++i)
    {
        int tpre = pre;
        tpre += (pos - d)*i;
        ans += dfs(pos - 1,d,tpre,(limit && i == end));
    }
    if (!limit) dp[pos][d][pre] = ans;

    return ans;
}

ll solve(ll n)
{
    int pos = 0;
    while (n)
    {
        bit[pos++] = n%10;
        n /= 10;
    }
    ll ans = 0;
    for (int i = 0; i < pos; ++i) ans += dfs(pos - 1,i,0,1);

    return ans - (pos - 1);
}

int main()
{
//    Read();
    int T;
    ll x,y;
    cin>>T;
    CL(dp,-1);
    while (T--)
    {
        cin>>x>>y;
        cout<<solve(y) - solve(x - 1)<<endl;
    }
    return 0;
}
View Code

还存在另一种解法:

间分解:[X, Y] = [0, Y] - [0, X-1]

对于小于X的数,我们需要判定它是不是balance数:

digit(i)表示数的第i个数字

数字和:sdig=sum(digit(i))               {i=1..n }

数字位权和:snum=sum(i*digit(i))           {i=1..n}

每一次判断数是不是平衡的,就看snum%sdig是不是0.

我们首先假设中间值在最高为的左边 4139   在4的左边,我们倒着将数取出来之后在-1位置,当我们将中间值向右移动时每次多的一边会减少sdig

// BEGIN CUT HERE

// END CUT HERE
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll long long
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d
", x)
#define lowbit(x)   (x)&(-x)
#define Read()  freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 5007
#define N 1007
using namespace std;

ll dp[20][170][2000];
int bit[20];
//位置,数字和,加权和,是否有限制
ll dfs(int pos,int sd,int s,int limit)
{
    if (pos == -1) return sd == 0 || s%sd == 0;
    if (!limit && dp[pos][sd][s] != -1) return dp[pos][sd][s];

    int end = limit? bit[pos] : 9;
    ll ans = 0;
    for (int i = 0; i <= end; ++i)
    {
        int tsd = sd + i;
        int ts = s + pos*i;
        ans += dfs(pos - 1,tsd,ts,limit && i == end);
    }
    if (!limit) dp[pos][sd][s] = ans;
    return ans;

}
ll solve(ll n)
{
    int pos = 0;
    while (n)
    {
        bit[pos++] = n%10;
        n /= 10;
    }
    return dfs(pos - 1,0,0,1);
}
int main()
{
    int T;
    ll x,y;
    cin>>T;
    CL(dp,-1);
    while (T--)
    {
        cin>>x>>y;
        cout<<solve(y) - solve(x - 1)<<endl;
    }
    return 0;
}
View Code

 hdu 4507 吉哥系列故事——恨7不成妻

题意:

中文...

思路:

这道题目的难度还是不好想的,关键在于平方和的维护。

我们首先求出整个区间[0,R]的所有数的平方和,然后见去与7有关的平方和即可。 如何求该区间与7有关的平方和呢。 要是求该区间的个数的话,就很简单了。模板就可。

我们假设我们枚举的当前位为pos位,且在该位的数子是i,后缀满足的个数为n,  所有后缀的平方和为k1^2 + k2^2 + ... + kn^2; 那么我们 ki为后缀这个数。

则x = i*10^(cnt - 1);

那么此时满足的平方和为  (i*x + k1)^2 + (i*x + k2)^2 + ... (i*x + kn)^2  展开后的:
n*(i*x)^2 + 2*i*x*(k1 + k2 + ... + kn) + (k1^2 + k2^2 + ..... + kn^2);  由此我们可以发现,如果要得到满足条件的平方和,我们维护三个部分,后缀满足的个数n,所有满足条件的后缀的和,所有满足条件的后缀的平方和。

还要用到一个数学公式 :1^2 + 2^2 + 3^2 + ... + n^2 = n*(n + 1)*(2*n + 1)/6;

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll long long
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d
", x)
#define lowbit(x)   (x)&(-x)
#define Read()  freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 137
#define N 27

using namespace std;


const int inf = 0x7f7f7f7f;
const ll mod = 1000000007;

struct node
{
    ll cnt;//后缀满足的个数
    ll sum1;//所有满足条件的后缀的和
    ll sum2;//所有满足条件的后缀的平方和。
    void init()
    {
        cnt = sum1 = sum2 = 0;
    }
    void install()
    {
        cnt = sum1 = sum2 = -1;
    }
}dp[N][10][10][2];
ll fac[N];
int bit[N];

node dfs(int pos,int a,int b,int c,int limit)
{
    if (pos == 0)
    {
        dp[pos][a][b][c].init();
        if (a && b && !c) dp[pos][a][b][c].cnt = 0;
        else dp[pos][a][b][c].cnt = 1;
        return  dp[pos][a][b][c];
    }
    if (!limit && dp[pos][a][b][c].cnt != -1) return dp[pos][a][b][c];

    int end = limit? bit[pos - 1] : 9;
    node ans; ans.init();
    for (int i = 0; i <= end; ++i)
    {
        int ta = (a*10 + i)%7;
        int tb = (b + i)%7;
        int tc = c;
        if (i == 7) tc = 1;
        node tmp = dfs(pos - 1,ta,tb,tc,limit && i == end);

        //关键是这里的计算n*(i*x)^2 + 2*i*x*(k1 + k2 + ... + kn) + (k1^2 + k2^2 + ..... + kn^2);
        ll x = i*fac[pos - 1]%mod;
        ans.cnt = (ans.cnt + tmp.cnt)%mod;
        ans.sum1 =((ans.sum1 +  tmp.sum1)%mod + tmp.cnt*x%mod)%mod;
        ans.sum2 = (((ans.sum2 + tmp.cnt*x%mod*x%mod)%mod + tmp.sum2)%mod + 2*tmp.sum1*x%mod)%mod;
    }
    return limit ? ans : dp[pos][a][b][c] = ans;
}

ll SUM(ll m)
{
    ll a = m,b = m + 1,c = 2*m + 1;
    int x = 3,y = 2;
    //肯定能够把x和y除了
    if (a%x == 0) a /= x,x = 1; if (a%y == 0) a /= y, y = 1;
    if (b%x == 0) b /= x,x = 1; if (b%y == 0) b /= y, y = 1;
    if (c%x == 0) c /= x,x = 1; if (c%y == 0) a /= y, y = 1;
    a %= mod; b %= mod; c %= mod;
    return a*b%mod*c%mod;
}
ll solve(ll n)
{
    int pos = 0;
    ll m = n;
    while (n)
    {
        bit[pos++] = n%10;
        n /= 10;
    }
    return (SUM(m) - dfs(pos,0,0,0,1).sum2 + mod)%mod;
}
void init()
{
    fac[0] = 1;
    for (int i = 1; i <= 20; ++i)
    {
        fac[i] = fac[i - 1]*10%mod;
    }
    for (int i = 0; i <= 20; ++i)
    {
        for (int j = 0; j < 7; ++j)
        {
            for (int k = 0; k < 7; ++k)
            {
                for (int p = 0; p < 2; ++p)
                {
                    dp[i][j][k][p].install();
                }
            }
        }
    }
}
int main()
{
//    Read();
    init(); int T;
    cin>>T; ll x,y;
    while (T--)
    {
        cin>>x>>y;
        cout<<(solve(y) - solve(x - 1) + mod)%mod<<endl;
    }
    return 0;
}
View Code

fzu 2113 Jason的特殊爱好

题意: 中文

思路:
当我们枚举完后缀时,价差一下最高为是否为1,如果为1的话,在看当前为是否有限,如果有限的话,就只能加上后缀 + 1了,如果无线的话就是0 -- 9999***了

例如  331454 假设我们枚举到了21****这时是没有限制的那么我们就可以加上9999 +1个了,如果枚举到了331***我们只能加454了

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll long long
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d
", x)
#define lowbit(x)   (x)&(-x)
#define Read()  freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 5007
#define N 1007
using namespace std;


ll dp[20][10];
int bit[20];
ll fac[20],s[20];

ll dfs(int pos,int lt,int lm)
{
    if (pos == -1) return lt == 1;
    if (!lm && dp[pos][lt] != -1) return dp[pos][lt];

    int end = lm? bit[pos] : 9;
    ll ans = 0;
    for (int i = 0; i <= end; ++i)
    {
        ans += dfs(pos - 1,i,lm && i == end);
    }
    if (lt == 1)
    {
        if (!lm) ans += fac[pos + 1];
        else ans += s[pos] + 1;
    }
    return lm ? ans : dp[pos][lt] = ans;

}
ll solve(ll n)
{
    int pos = 0;
    ll m = n;
    while (n)
    {
//        cout << n << endl;
        bit[pos] = n%10; n /= 10;
        s[pos] = m%fac[pos + 1];//把我们需要的后缀取出来
        pos++;
    }
    return dfs(pos - 1,0,1);
}
void init()
{
    fac[0] = 1;
    for (int i = 1; i < 20; ++i) fac[i] = fac[i - 1]*10;
    CL(dp,-1);
}
int main()
{
//    Read();
    ll x,y;
    init();
    while (cin>>x>>y)
    {
        cout<<solve(y) - solve(x - 1)<<endl;
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/E-star/p/3143071.html