D2. Submarine in the Rybinsk Sea (hard edition)(思维+位数思考+组合数学)

https://codeforces.com/problemset/problem/1195/D2

题意翻译

题目描述

这题与上一个题的不同之处仅在于存在使所有数字 a_1,a_2,\dots,a_na1​,a2​,…,an​ 的无长度相等的约束。

SISSIS 学生团队将乘坐潜水艇去旅游,他们的目标是位于大雷宾斯克 (Rybinsk)(Rybinsk) 海底沉船中的古代宝藏。不幸的是,学生们不知道船的坐标,因此他们要求 MeshanyaMeshanya(一位世袭魔法师)来帮助他们。MeshanyaMeshanya 同意帮助他们,但前提是他们得解决了 MeshanyaMeshanya 的问题。

让我们用一个函数 f(a_1a_2\dots a_{p-1}a_p,b_1b_2\dots b_{p-1}b_p)f(a1​a2​…ap−1​ap​,b1​b2​…bp−1​bp​) 来交替两个数字的各位数码,其中 a_1,a_2,\dots,a_pa1​,a2​,…,ap​ 和 b_1,b_2,\dots,b_pb1​,b2​,…,bp​ 是以十进制表示的两个整数的数码,不含前导零。

换句话说,函数 f(x,y)f(x,y) 通过将数字 xx 和 yy 的各位数码从最低位数写到较高位数字,从数字 yy 开始,交替地插入数字 xx 和 yy。该函数的结果也是从右到左构建的(即从较低的数字到较旧的数字)。如果其中一个参数(不妨设为 xx)的数字已写完,则写下另一个参数(即 yy)的剩余数字,下面我们来看几个例子熟悉一下。

f(1111, 2222) = 12121212f(1111,2222)=12121212

f(7777, 888) = 7787878f(7777,888)=7787878

f(33, 44444) = 4443434f(33,44444)=4443434

f(555, 6) = 5556f(555,6)=5556

f(111, 2222) = 2121212f(111,2222)=2121212

一般的,如果 p \ge qp≥q,那么 f(a_1 \dots a_p, b_1 \dots b_q) = (a_1 a_2 \dots a_{p - q + 1} b_1 a_{p - q + 2} b_2 \dots a_{p - 1} b_{q - 1} a_p b_q)_{(10)}f(a1​…ap​,b1​…bq​)=(a1​a2​…ap−q+1​b1​ap−q+2​b2​…ap−1​bq−1​ap​bq​)(10)​ MishanyaMishanya 为您提供一个由 nn 个整数组成的数组 \{a_i\}{ai​}。你的任务是帮助学生们计算 \sum\limits_{i = 1}^{n}\sum\limits_{j = 1}^{n} f(a_i, a_j) \mod 998244353i=1∑n​j=1∑n​f(ai​,aj​)mod998244353

输入格式

输入的第一行包含一个整数 n(1 \le n \le 100000)n(1≤n≤100000)。输入的第二行包含 nn 个整数 a_1,a_2,\dots,a_n(1\le a_i\le10^9)a1​,a2​,…,an​(1≤ai​≤109),所有数字长度相同,它们即位数相等。

输出格式

答案模 998244353998244353。

输入输出样例

输入 #1复制

3
12 3 45

输出 #1复制

12330

输入 #2复制

2
123 456

输出 #2复制

1115598

思路:暴力去做是n^2的。像这种题比较经典的转化是枚举位去优化。

统计每个数的每一位,同时枚举和每一个长度为1~10的数字进行f的贡献

比如n=2

12 231. 那么过程是f(12,12)+f(12,231)+f(231,12)+f(231,231)

考虑枚举到12,12和长度为2,3的数字去统计过程。

比如12 和231,12的2的贡献在f(12,231)的时候贡献是 21321的十位,而题目求和是n^2的求和,光统计这个不够,12的2在f(231,12)的时候也有贡献,是2的个位。这里在模拟之后得出来分别是siz*pw[cur*2-1]*p和siz*pw[cur*2-2]*p。

 siz是长度为1/2/3/...10的个数,pw[]是预处理出来的十进制的阶乘。

然后比如考虑231和12,231的2的贡献在f(231,12)的时候贡献的是23112,这个2在万位。而题目求和是n^2的求和,光统计这个不够,231的2在f(12,231)的时候是21321,也是万位。综合一下是乘2的过程。

挺好一题

#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;

typedef long long LL;

const int N = 100100;
const int mod = 998244353;

LL a[N], cnt[100], sz[N];
LL pw[100];
LL times=0;
LL cal(LL x,LL len,LL siz)
{
    LL cur=0;
    LL ans=0;
  //  debug(len);
  //  debug(siz);
    while(x)
    {
        cur++;
        LL p=x%10;
   //     debug(p);
        x/=10;
        times++;
        if(cur<=len){
            ans=(ans%mod+siz*pw[cur*2-1]*p%mod)%mod;
        //    cout<<"times: "<<"p="<<p<<"  "<<siz*pw[cur*2-1]*p<<endl;
            ans=(ans%mod+siz*pw[cur*2-2]*p%mod)%mod;
        //    cout<<"times: "<<"p="<<p<<" "<<siz*pw[cur*2-2]*p<<endl;
            //cout<<"siz*pw[(cur*2)]*p%mod="<<siz*pw[(cur*2)]*p%mod<<endl;
            //debug(ans);
        }
        else{
            ans=(ans%mod+2*siz*p*pw[len+cur-1]%mod)%mod;
      //      cout<<"times: "<<"p="<<p<<"  "<<siz*p*pw[len+cur-1]<<endl;
            //debug(ans);
        }
        
    }
    return ans;
}
LL getlen(LL x)
{
    LL l=0;
    while(x)
    {
        l++;
        x/=10;
    }
    return l;
}
int main() {
    LL n;
    scanf("%lld", &n);
    pw[0] = 1;//因为后面用while(x)取位,所以初始化p[0]=1;
    for (LL i = 1; i <= 31; i++) pw[i] = pw[i-1] * 10 % mod;
    for (LL i = 1; i <= n; i++) {
        scanf("%lld",&a[i]);
        cnt[getlen(a[i])]++;
    }
    LL res = 0;
    for (LL i = 1; i <= n; i++) {
        LL b = a[i];
        for(LL j=1;j<=10;j++){
            if(cnt[j])
            {
               res=(res%mod+cal(b,j,cnt[j])%mod)%mod; 
            }
        }
    }
    printf("%lld\n", res);
}

猜你喜欢

转载自blog.csdn.net/zstuyyyyccccbbbb/article/details/108548215
今日推荐