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
  • 相关阅读:
    HAproxy 1.5 dev14 发布
    IBM/DW 使用 Java 测试网络连通性的几种方法
    Skype 4.1 Linux 发布,支持微软帐号登录
    Dorado 7.1.20 发布,Ajax的Web开发平台
    Aspose.Slides for Java 3.0 发布
    开发版本 Wine 1.5.18 发布
    BitNami Rubystack 开始支持 Ruby 2.0
    XWiki 4.3 正式版发布
    Silverlight实例教程 Out of Browser的Debug和Notifications窗口
    Silverlight实例教程 Out of Browser与Office的互操作
  • 原文地址:https://www.cnblogs.com/E-star/p/3143071.html
Copyright © 2011-2022 走看看