数位统计练习

论文:

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\n", 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\n", 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\n",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\n", 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\n", 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\n", 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\n", 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\n", 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\n", 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

 

 

你可能感兴趣的:(统计)