• Codeforces


    https://codeforc.es/problemset/problem/1195/D2

    很明显可以看出,任意一个长度为(l_1)的数串(s_1)和任意一个长度为(l_2)的数串(s_2)(f(s_1,s_2))中每个位的贡献的位数是一样的。稍微推一推可以知道,(calcx\_ijk)(calcy\_ijk)的公式。然后暴力统计一波各个长度的数串有几个就可以了。小心溢出。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
     
    ll a[100005];
    ll di[100005][11];
    int cntws[11];
     
    ll gx[11][11][11];
    ll gy[11][11][11];
     
    const ll mod = 998244353;
     
    int ws(ll x) {
        int cnt = 0;
        while(x) {
            //cout<<x<<" ";
            cnt++;
            x /= 10;
            //cout<<cnt<<endl;
        }
        return cnt;
    }
     
    ll ans;
     
    ll calc_base(int i,int k){
        ll res=0;
        for(int j=1;j<=10;j++){
            res=(res+1ll*cntws[j]*gx[i][j][k]%mod)%mod;
            res=(res+1ll*cntws[j]*gy[i][j][k]%mod)%mod;
        }
        //cout<<"i="<<i<<" k="<<k<<" res="<<res<<endl;
        return res;
    }
     
    ll calc(ll x) {
        ll res = 0;
        int i=ws(x);
        for(int k=1;k<=i;k++){
            ll r = x%10;
            res = (res + calc_base(i,k)* r % mod) % mod;
            x /= 10;
        }
        return res % mod;
    }
     
    ll p10[23];
     
    ll calc_ijk(int i, int j, int k) {
        if(k <= j) {
            return p10[k * 2];
        } else {
            return p10[j + k];
        }
    }
     
    ll calc_ijk2(int i, int j, int k) {
        if(k <= j) {
            return p10[k * 2 - 1];
        } else {
            return p10[j + k];
        }
    }
     
    void init_gx() {
        memset(gx, 0, sizeof(gx));
        //gx[i][j][k]i是x,j是y的时候,导致i的第k位贡献的位数
        //gy[i][j][k]i是x,j是y的时候,导致j的第k位贡献的位数
        for(int i = 1; i <= 10; i++) {
            for(int j = 1; j <= 10; j++) {
                for(int k = 1; k <= i; k++) {
                    gx[i][j][k] = calc_ijk(i, j, k);
                }
            }
        }
        memset(gy, 0, sizeof(gy));
        //gx[i][j]i是x,j是y的时候,导致i贡献的位数
        //gy[i][j]i是x,j是y的时候,导致j贡献的位数
        for(int i = 1; i <= 10; i++) {
            for(int j = 1; j <= 10; j++) {
                for(int k = 1; k <= i; k++) {
                    gy[i][j][k] = calc_ijk2(i, j, k);
                }
            }
        }
    }
     
    int main() {
    #ifdef Yinku
        freopen("Yinku.in", "r", stdin);
        //freopen("Yinku.out", "w", stdout);
    #endif // Yinku
        p10[1] = 1;
        for(int i = 2; i <= 21; i++) {
            p10[i] = p10[i - 1] * 10ll % mod;
            //cout<<p10[i]<<endl;
        }
        int n;
        init_gx();
        for(int i = 1; i <= 2; i++) {
            for(int j = 1; j <= 2; j++) {
                for(int k = 1; k <= i; k++) {
                    gx[i][j][k] %= mod;
                    gy[i][j][k] %= mod;
                    //printf("%lld ",gx[i][j][k]);
                    //printf("%lld",gy[i][j][k]);
                }
                //printf("
    ");
            }
            //printf("
    ");
        }
        while(~scanf("%d", &n)) {
            memset(cntws, 0, sizeof(cntws));
            for(int i = 1; i <= n; ++i) {
                scanf("%lld", &a[i]);
                cntws[ws(a[i])]++;
                //cout<<ws(a[i])<<endl;
            }
            /*for(int i = 1; i <= 10; ++i) {
                //cout<<cntws[i]<<endl;
            }*/
            ans = 0;
            for(int i = 1; i <= n; i++) {
                ans = (ans + calc(a[i])) % mod;
                //printf("ans=%lld
    ", ans % mod);
            }
            printf("%lld
    ", ans % mod);
        }
    }
    

    发现其实可以缩写成下面的形式:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int mod = 998244353;
    
    int a[100005];
    int lena[100005];
    int cntlen[11];
    
    int g[11][11][11];
    
    int len(int x) {
        int cnt = 0;
        while(x) {
            cnt++;
            x /= 10;
        }
        return cnt;
    }
    
    ll ans;
    
    ll calc_base(int i, int k) {
        ll res = 0;
        for(int j = 1; j <= 10; j++)
            res = (res + 1ll * g[i][j][k] * cntlen[j] % mod) % mod;
        return res;
    }
    
    ll calc(int x, int lenx) {
        ll res = 0;
        for(int k = 1; k <= lenx; k++) {
            int r = x % 10;
            res = (res + calc_base(lenx, k) * r % mod) % mod;
            x /= 10;
        }
        return res % mod;
    }
    
    int p10[21];
    
    void init_g() {
        memset(g, 0, sizeof(g));
        //g[i][j][k]是两个数分别是i位,j位时候,导致长度为i的第k位发生的贡献
        for(int i = 1; i <= 10; i++)
            for(int j = 1; j <= 10; j++)
                for(int k = 1; k <= i; k++)
                    g[i][j][k] = (p10[k + ((k <= j) ? k : j)] + p10[k + ((k <= j) ? (k - 1) : j)]) % mod;
    }
    
    void init_p10() {
        p10[1] = 1;
        for(int i = 2; i <= 20; i++) {
            p10[i] = p10[i - 1] * 10ll % mod;
        }
    }
    
    int main() {
    #ifdef Yinku
        freopen("Yinku.in", "r", stdin);
        //freopen("Yinku.out", "w", stdout);
    #endif // Yinku
        init_p10();
        init_g();
        int n;
        while(~scanf("%d", &n)) {
            memset(cntlen, 0, sizeof(cntlen));
            for(int i = 1; i <= n; ++i) {
                scanf("%d", &a[i]);
                lena[i] = len(a[i]);
                cntlen[lena[i]]++;;
            }
            ans = 0;
            for(int i = 1; i <= n; i++) {
                ans = (ans + calc(a[i], lena[i])) % mod;
            }
            printf("%lld
    ", ans);
        }
    }
    
  • 相关阅读:
    CSDNReader(android客户端)发布!!
    linux下的C语言快速学习—从1+1开始。
    linux下的C语言快速学习—进程和文件
    ListView动态加载数据分页(使用Handler+线程和AsyncTask两种方法)
    CSDN阅读器(android版)开发总结
    算法实现将一个输入的数字颠倒(输入12345>54321)
    linux下的C语言快速学习—计算机体系结构基础简单了解
    实现一个字符串查找子串的函数
    .net4.0面向对象学习笔记—数据类型
    装饰器模式
  • 原文地址:https://www.cnblogs.com/Yinku/p/11205502.html
Copyright © 2020-2023  润新知