Yiwen with Sqc

题目链接:https://acm.hdu.edu.cn/showproblem.php?pid=7055

s u m [ a ] [ i ] sum[a][i] sum[a][i] 1 − i , a 1-i,a 1ia字符的个数
原式
∑ c = 97 122 ∑ i = 1 n ∑ j = i n s q c ( s , i , j , c ) = ∑ c = 97 122 ∑ i = 1 n ∑ j = i n ( s u m [ c ] [ j ] − s u m [ c ] [ i − 1 ] ) 2 \sum_{c=97}^{122}\sum_{i=1}^{n}\sum_{j=i}^{n}sqc(s,i,j,c) \\{=\sum_{c=97}^{122}\sum_{i=1}^{n}\sum_{j=i}^{n}{(sum[c][j]-sum[c][i-1])^2}} c=97122i=1nj=insqc(s,i,j,c)=c=97122i=1nj=in(sum[c][j]sum[c][i1])2 = ∑ c = 97 122 ∑ i = 1 n ∑ j = 1 n ( s u m 2 [ c ] [ j ] − 2 ∗ s u m [ c ] [ j ] ∗ s u m [ c ] [ i − 1 ] + s u m 2 [ c ] [ i − 1 ] ) {=\sum_{c=97}^{122}\sum_{i=1}^{n}\sum_{j=1}^{n}(sum^2[c][j]-2*sum[c][j]*sum[c][i-1]+sum^2[c][i-1])} =c=97122i=1nj=1n(sum2[c][j]2sum[c][j]sum[c][i1]+sum2[c][i1])
= ∑ c = 97 122 ∑ i = 1 n ∑ j = i n s u m 2 [ c ] [ j ] − 2 ∗ s u m [ c ] [ i − 1 ] ∗ ∑ j = i n s u m [ a ] [ j ] + ∑ j = i n s u m 2 [ c ] [ i − 1 ] {= \sum_{c=97}^{122}\sum_{i=1}^{n}{\sum_{j=i}^{n}sum^2[c][j]-2*sum[c][i-1]*\sum_{j=i}^{n}sum[a][j]+\sum_{j=i}^{n}sum^2[c][i-1]}} =c=97122i=1nj=insum2[c][j]2sum[c][i1]j=insum[a][j]+j=insum2[c][i1]

此时我们可以发现一个 O ( 26 ∗ n ) O(26*n) O(26n)的做法:前缀和记录 s u m [ c ] [ j ] , ∑ j = 1 n s u m 2 [ c ] [ j ] , ∑ j = 1 n s u m [ c ] [ i ] sum[c][j],\sum_{j=1}^nsum^2[c][j],\sum_{j=1}^{n}sum[c][i] sum[c][j],j=1nsum2[c][j],j=1nsum[c][i],然后遍历 i , c i,c i,c
但遗憾的是这个做法会T(不过也有可能是我的写法的锅?)

其实上面方法还可以优化:在一段没有 c c c字符的字符串里, s u m [ c ] [ j ] , ∑ j = 1 n s u m 2 [ c ] [ j ] , ∑ j = i n s u m [ c ] [ i ] sum[c][j],\sum_{j=1}^nsum^2[c][j],\sum_{j=i}^{n}sum[c][i] sum[c][j],j=1nsum2[c][j],j=insum[c][i]是等差的,公差分别 0 , − s u m 2 [ c ] [ j ] , − s u m [ c ] [ j ] 0,-sum^2[c][j],-sum[c][j] 0,sum2[c][j],sum[c][j],这也就代表着我们可以通过等差求和快速求得这段的贡献,当然,解决问题时我们总是取两端都是 c c c的字符的中间部分,这样对每一个 c c c,我们只要进行 2 ∗ c n t c 2*cntc 2cntc次计算就可以,也就是说可以大概 O ( 2 n ) O(2n) O(2n)解决

AcCode:

#include <iostream>
#include <algorithm>
#include <stack>
#include <cstdio>
#include <cmath>
#include <string>
#include <set>
#include <map>
#include <vector>

#define int long long
#define eps 0.00000001
#define pint std::pair<int,int>

const int N = 1e5 + 100;
const int mod = 998244353;

int sum[N];
int mul[N];
int rem[N];
int number[N];
char str[N];

std::vector<int> vec[30];

inline int mu(const int& a, const int& b) { return a * b % mod; }

signed main() {
    std::ios::sync_with_stdio(false);
    int t; std::cin >> t;
    while (t--) {
        int ans = 0;
        std::cin >> (str + 1);
        int len = std::strlen(str + 1);
        for (int i = 0; i < 26; i++) vec[i].clear();
        for (int i = 1; i <= len; i++) {
            number[i] = (int)str[i] - 97;
            vec[number[i]].push_back(i);
        }
        for (int a = 0; a < 26; a++) {
            sum[0] = rem[0] = mul[0] = 0;
            int last = 0;
            for (auto& v : vec[a]) sum[v] = sum[last] + 1, last = v;//
            sum[len] = sum[last];
            last = 0;
            for (auto& v : vec[a]) rem[v] = (rem[last] + sum[last] * (v - last - 1) + sum[v]), last = v;
            rem[len] = (rem[last] + sum[last] * (len - last));
            last = 0;
            for (auto& v : vec[a]) mul[v] = (mul[last] + (sum[last] * sum[last] * (v - last - 1)) + sum[v] * sum[v]) % mod, last = v;
            mul[len] = (mul[last] + sum[last] * sum[last] * (len - last)) % mod;
            last = 0;
            for (auto& v : vec[a]) ans = ((mul[len] - mul[v] + sum[v] * sum[v] - 2ll * mu((sum[v] - 1), (rem[len] - rem[v] + sum[v])) + (len - v + 1) * mu((sum[v] - 1), (sum[v] - 1))) % mod + mod + ans) % mod;
            vec[a].insert(vec[a].begin(), 0);
            for (int i = 1; i < vec[a].size(); i++) {
                int l = vec[a][i - 1] + 1;
                int r = vec[a][i] - 1;
                if (l > r) continue;
                int tlen = r - l + 1;
                int add1 = mu((mul[len] - mul[l - 1]), tlen) - mu((tlen * tlen - tlen) / 2, mu(sum[l - 1], sum[l - 1]));//第一段
                int sub2 = mu(2 * sum[l - 1], mu(tlen, rem[len] - rem[l - 1]) - mu((tlen * tlen - tlen) / 2, sum[l - 1]));//的二段
                int add3 = mu(mu(sum[l - 1], sum[l - 1]), ((2 * len - l - r + 2) * tlen) / 2);//第三段
                add1 = (add1 % mod + mod) % mod;
                sub2 = (sub2 % mod + mod) % mod;
                add3 = (add3 % mod + mod) % mod;
                ans = ans + add1 - sub2 + add3;
                ans = (ans % mod + mod) % mod;

            }
        }
        std::cout << ans % mod << std::endl;
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值