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);
    }
}
原文地址:https://www.cnblogs.com/Yinku/p/11205502.html