HDU7055 - Yiwen with Sqc


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

思路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;
    }
}


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM