zoukankan      html  css  js  c++  java
  • 数位统计练习

    论文:

    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
  • 相关阅读:
    Python Package(转)
    22. 分数化小数 decimal
    21. 子序列的和 subsequence
    20. 倒三角形 triangle
    19. 韩信点兵hanxin
    18. 水仙花数daffodil
    17. 数据统计2
    16. 数据统计
    15. 阶乘之和
    14. 近似计算
  • 原文地址:https://www.cnblogs.com/E-star/p/3143071.html
Copyright © 2011-2022 走看看