【2021杭电多校第七场】Yiwen with Sqc

题目链接:

https://acm.hdu.edu.cn/showproblem.php?pid=7055

题目大意:

给一个字符串,对于每个小写字母ch,问所有区间内ch出现次数的平方和,其中|s|<10^{5}

\sum_{c=97}^{122}\sum_{i=1}^{n}\sum_{j=1}^{n} sqc(l,r,ch)^{2} 

因为答案很大,所以对998244353取模(答案很大,忍一下

解题思路:

朴素算法,像公式那样,遍历每个区间,相加。但是因为长度是1e5肯定会TLE

对于这种区间问题,我们往往采用差分或者前缀和

这题赛场上就想到了用前缀和

对于一个字母ch,我们定义 s[i]为到i为止,ch出现的个数

那么每个区间[,r]的答案就是(s[r] - s[l - 1])^{2}

ans = \sum_{i=1}^{n}\sum_{j=i}^{n} (s[j]-s[i-1])^{2}

我们将平方和拆开化简

就会得到 ans= (n+1) * \sum_{i=1}^{n}s[i]^{2} - (\sum_{i=1}^{n}s[i])^{2}

然后时间复杂度就会变成O(26n)

(可以统计字母出现的种类tot,时间复杂度优化到O(tot*n))赛场上卡常过了,赛后T了

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1e5 + 3;
const int MOD = 998244353;
ll a[27][N];
int b[27], cc[27];
int main() {
    int T;
    scanf ("%d", &T);
    while (T--) {
        string s;
        cin >> s ;
        int len = s.length();
        memset (a, 0, sizeof (a) );
        memset (b, 0, sizeof (b) );
        for (int i = 0; i < len; i++) {
            b[s[i] - 'a' + 1] = 1;
            a[s[i] - 'a' + 1][i]++;
        }
        int tot = 0;
        for (int i = 1; i <= 26; i++)
            if (b[i])
                cc[++tot] = i;
        ll ans = 0;
        ll tt = 0, t = 0;
        for (int k = 1; k <= tot; k++) {
            tt = 0, t = 0;
            int c = cc[k];
            for (int i = 0; i < len; i++) {
                a[c][i] = a[c][i - 1] + a[c][i];
                t = (ll) (t + a[c][i] * a[c][i] % MOD) % MOD;
                tt =
                 (ll) (tt + a[c][i]) % MOD;
            }
            ans += ( (len + 1) * t % MOD - tt * tt % MOD + MOD) % MOD;
            ans %= MOD;
        }
        printf ("%lld\n", ans);
    }
    return 0;
}

我们可以想一想,怎么样改进

我们的思路是求前缀和的和,和前缀和平方和。

我们可以发现一段前缀和的值,在一个区间内是一样的,并且这个区间长度是可以知道的。而前缀和的平方和其实就是在区间内当前字母的个数*当前这一段的长度。

对于字a在字符串ababa举例:

i0123456
字母\a

b

aba\
维持长度221
s[i]011223

对于前缀和的和

我们可以用 1 * 2 + 2 * 2 + 3 * 1 = 9 算

对于前缀和的平方和

我们可以用 1^{2} * 2 + 2^{2}* 2 + 3^{2}*1 来算

这上面的 2 2 1 其实是这一个ch对前缀和影响的长度

用a[i]来保存序列中第i个ch出现的位置

用len[i]表示第i个ch维持的长度

len[i]=a[i + 1]-a[i]

令区间内出现ch的次数为cnt

len[cnt]=n+1-a[cnt]

因此我们的答案就变成了

ans=(n+1)*\sum_{i=1}^{cnt}i*i*len[i] -\sum_{i=1}^{cnt}*i*len[i]

这样跑的就非常的快

代码实现:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1e5 + 3;
const int MOD = 998244353;
char s[N];
void work() {
    scanf ("%s", s);
    int len = strlen (s);
    vector<int>a[27];
    for (int i = 1; i <= 26; i++) a[i].push_back (0);
    for (int i = 0; i < len; i++) {
        a[s[i] - 'a' + 1].push_back (i + 1);
    }
    ll ans = 0;
    for (int i = 1; i <= 26; i++) {
        a[i].push_back (len + 1);
        ll t1 = 0, t2 = 0;
        for (int j = 1; j + 1 < a[i].size(); j++) {
            t1 += (ll)j * (a[i][j + 1] - a[i][j]) % MOD;
            t2 += (ll)j * j % MOD * (a[i][j + 1] - a[i][j]) % MOD;
            t1 %= MOD;
            t2 %= MOD;
        }
        ans += ( (ll) (len + 1) * t2 % MOD - t1 * t1 % MOD + MOD ) % MOD;
        ans %= MOD;
    }
    printf ("%lld\n", ans);

}
int main() {
    int T;
    scanf ("%d", &T);
    while (T--)
        work();
    return 0;
}

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是其他几篇2022年关于图像分类的外文文献和相关代码地址: 1. 论文题目:"Adversarial Training with Feature Ensembles for Robust Image Classification" 论文作者:Yinpeng Chen, Haibo Chen, Jingyi Wang, and Liang Lin 期刊/会议:CVPR 2022 论文简介:本文提出了一种基于特征集成的对抗训练方法,用于提高图像分类模型的鲁棒性。该方法利用不同的特征提取器进行训练,并通过对抗样本生成器来增强模型的鲁棒性。实验结果表明,该方法可以有效地提高图像分类的准确率和鲁棒性。 代码地址:https://github.com/yinpengchen/Adv-Ensemble 2. 论文题目:"Multi-Scale Attention for Image Classification" 论文作者:Shiwei Zhang, Zhiyuan Chen, Xiaolin Hu, and Jun Zhu 期刊/会议:CVPR 2022 论文简介:本文提出了一种基于多尺度注意力机制的图像分类方法,称为MSA。该方法可以自适应地学习不同尺度的特征表示,并在分类任务中取得了最先进的性能。MSA采用一种新的注意力损失函数,可以有效地训练深度神经网络。 代码地址:https://github.com/anonymous-cvpr2022/msa_classification 3. 论文题目:"Instance-Level Adversarial Training for Image Classification" 论文作者:Yiwen Guo, Junjie Yan, Kai Chen, and Gang Hua 期刊/会议:CVPR 2022 论文简介:本文提出了一种基于实例级对抗训练的图像分类方法,称为ILAT。该方法可以在保持分类准确率的情况下提高模型的鲁棒性,并对抗针对单个样本的攻击。ILAT采用一种新的对抗损失函数,并采用一种新的样本选择策略来提高训练效率。 代码地址:https://github.com/anonymous-cvpr2022/ilat_classification

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值