[NOI.AC] palindrome

思路:

$50pts$
$f[l,r]$表示区间$[l,r]$能够变成多少个串,转移枚举$l$,利用$hash$判字符串相等。
复杂度$O(Tn^3)$

$70pts$
考虑优化,发现$f[1,n]$的贡献来源于每个$f[i,n - i + 1]$,所以dp过程降低复杂度为$O(Tn^2)$。

$100pts$
枚举$border$每次贪心的砍$border$,被卡单$hash$一脸不爽$.jpg$
不过判相等如果泥工$kmp$,恭喜你,贪心和没贪一样,因为复杂度还是$O(n^2)$
复杂度$O(Tn)$


#include <bits/stdc++.h>
using namespace std;
const int bse1 = 29;
const int bse2 = 33;
const int mod1 = 1e9+7;
const int mod2 = 1e9+9;
#define ull unsigned long long
const int maxn = 10000010;
char s[maxn]; 
ull hsh[maxn][2];
ull pw1[maxn];
ull pw2[maxn];
int T;
inline void pre () {
    pw1[0] = pw2[0] = 1;
    for(int i = 1;i < maxn; ++i) {
        pw1[i] = pw1[i - 1] * bse1 % mod1;
        pw2[i] = pw2[i - 1] * bse2 % mod2;
    }
}
inline ull cal1(int l,int r) {
    return (hsh[r + 1][0] - hsh[l][0] * pw1[r - l + 1] % mod1 + mod1) % mod1; 
}
inline ull cal2(int l,int r) {
    return (hsh[r + 1][1] - hsh[l][1] * pw2[r - l + 1] % mod2 + mod2) % mod2;
}
inline bool check(int x,int y,int l,int r) {
    return cal1(x,y) == cal1(l,r) && cal2(x,y) == cal2(l,r);
}
inline int solve(int l,int r) {
    if(l > r) return 0;
    for(int i = l;i < (r - (i - l)); ++i) {
        if(check(l,i,(r - (i - l)),r)) {
            return solve(i + 1,r - (i - l) - 1) + 2;
        }
    }
    return 1;
}
int main () {
    pre();
    scanf("%d",&T);
    while(T--) {
        scanf("%s",s);
        int len = strlen(s);
        for(int i = 0;i < len; ++i) {
            hsh[i + 1][0] = (hsh[i][0] * bse1 + s[i] - 'a') % mod1;
            hsh[i + 1][1] = (hsh[i][1] * bse2 + s[i] - 'a') % mod2;
        }
        printf("%d\n",solve(0,len - 1));
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/akoasm/p/9629239.html