思路1
考虑dp结果,dp[i]表示以i为结尾的答案
每次新进入一个字符,计算其对答案产生的贡献
char s[maxn];
int t, cnt[30], sum[30];
ll dp[maxn];
void solve() {
cin >> t;
while (t--) {
memset(cnt, 0, sizeof(cnt));
memset(sum, 0, sizeof(sum));
scanf("%s", s + 1);
int n = strlen(s + 1);
ll ans = 0;
for (int i = 1; i <= n; i++) {
int now = s[i] - 'a' + 1;
dp[i] = (dp[i - 1] + 2 * sum[now] + i) % mod;
sum[now] = (sum[now] + i) % mod;
ans = (ans + dp[i]) % mod;
}
printf("%lld\n", ans);
}
}
思路2
对每个字符分开考虑.
假设现在有a,b,c,d位置上有1,那么这个区间的贡献就是(1+1+1+1)^2,拆开来看
a^2 + b^2 + c^2 + d^2 + 2ab+2ac+2ad...
考虑c在这个区间产生的贡献: c^2 + 2ac + 2bc + 2cd,
那么对于[a-1,d],[a-2,d]...[a-x,d+y]求个sum就能得到c产生的答案,挨个计算每个1产生的贡献即可
其中用到了前缀和维护下就行
const int maxn = 1e5 + 7;
const int mod = 998244353;
int n, t, m;
char s[maxn];
int dp[maxn];
void solve() {
cin >> t;
while (t--) {
cin >> (s + 1);
n = strlen(s + 1);
ll res = 0;
for (char c = 'a'; c <= 'z'; c++) {
memset(dp, 0, sizeof(dp));
int cnt = 0, p = 0;
for (int i = 1; i <= n; i++) {
if (s[i] == c) {
res += i * (n - i + 1);
res %= mod;
++p, dp[p] = dp[p - 1] + i;
res += 2ll * (n - i + 1) * dp[p - 1];
res %= mod;
}
}
}
cout << res << endl;
}
}