• BZOJ 3160 万径人踪灭 解题报告


    这个题感觉很神呀。将 FFT 和 Manacher 有机结合在了一起。

    首先我们不管那个 “不能连续” 的条件,那么我们就可以求出有多少对字母关于某一条直线对称,然后记 $T_i$ 为关于直线 $i$ 对称的字母对的数量,那么答案(暂记为 $Ans$)就会是:

    $$Ans = sum 2^{T_i}-1$$

    在不管那个 “不能连续” 的条件的时候,这个应该是显然的。

    怎么算的话,我们弄两次。分别把 $a$ 和 $b$ 当做 $1$,另一个当做 $0$,然后就可以得到一个多项式,将这个多项式平方一下就可以得到所有的 $T_i$ 了,具体用 FFT 实现。

    那么我们来管一管这个条件。

    我们就可以用 Manacher 求出每一条直线的最长回文半径,然后记 $R_i$ 为直线 $i$ 的最长回文半径,那么实际上的总答案就会是:

    $$Ans - sum R_i$$

    然后就做完啦。令 $n$ 为字符串的长度:

    时间复杂度 $O(nlog n)$,空间复杂度 $O(n)$。

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 using namespace std;
      5 typedef long long LL;
      6 #define N 262144 + 5
      7 #define _Mod 1000000007
      8 #define Mod 998244353
      9 #define g 3
     10 
     11 int n, len, Inv_len, d, ans, e[2][N], Rev[N], A[N], T[N], R[N];
     12 char s[N];
     13 
     14 inline int Inc(int u, int v, int p)
     15 {
     16     return u + v - (u + v >= p ? p : 0);
     17 }
     18 
     19 inline int power(int u, int v, int p)
     20 {
     21     int res = 1;
     22     for (; v; v >>= 1)
     23     {
     24         if (v & 1) res = (LL) res * u % p;
     25         u = (LL) u * u % p;
     26     }
     27     return res;
     28 }
     29 
     30 inline void FFT_Prepare()
     31 {
     32     for (len = n << 1; len != (len & -len); len += (len & -len)) ;
     33     for (int i = len; i > 1; i >>= 1) d ++;
     34     int w = power(g, (Mod - 1) / len, Mod);
     35     int Inv_w = power(w, Mod - 2, Mod);
     36     Inv_len = power(len, Mod - 2, Mod);
     37     for (int i = 0; i < len; i ++)
     38     {
     39         e[0][i] = !i ? 1 : (LL) e[0][i - 1] * w % Mod;
     40         e[1][i] = !i ? 1 : (LL) e[1][i - 1] * Inv_w % Mod;
     41         for (int j = 0; j < d; j ++)
     42             if ((i >> j) & 1) Rev[i] += 1 << (d - j - 1);
     43     }
     44 }
     45 
     46 inline void FFT(int *p, int op)
     47 {
     48     for (int i = 0; i < len; i ++)
     49         if (Rev[i] > i) swap(p[Rev[i]], p[i]);
     50     for (int k = 1, s = 1; k < len; k <<= 1, s ++)
     51         for (int i = 0; i < len; i ++)
     52         {
     53             if (i & k) continue ;
     54             int t = (i & (k - 1)) << (d - s);
     55             int u = Inc(p[i], (LL) p[i + k] * e[op][t] % Mod, Mod);
     56             int v = Inc(p[i], (LL) (Mod - p[i + k]) * e[op][t] % Mod, Mod);
     57             p[i] = u, p[i + k] = v;
     58         }
     59 }
     60 
     61 inline void FFT_Work(char key)
     62 {
     63     memset(A, 0, sizeof(A));
     64     for (int i = 0; i < n; i ++)
     65         A[i] = (s[i] == key);
     66     FFT(A, 0);
     67     for (int i = 0; i < len; i ++)
     68         A[i] = (LL) A[i] * A[i] % Mod;
     69     FFT(A, 1);
     70     for (int i = 0; i < len; i ++)
     71         T[i] = Inc(T[i], (LL) A[i] * Inv_len % Mod, Mod);
     72 }
     73 
     74 inline void Manacher()
     75 {
     76     for (int i = (n << 1); i >= 0; i --)
     77         s[i] = i & 1 ? s[i >> 1] : 'c';
     78     int mx = -1, id;
     79     for (int i = 0; i <= (n << 1); i ++)    
     80     {
     81         if (mx > i)
     82             R[i] = min(R[id * 2 - i], mx - i);
     83         else R[i] = 1;
     84         for (; i + R[i] <= (n << 1) && i - R[i] >= 0 && s[i + R[i]] == s[i - R[i]]; R[i] ++) ;
     85         if (i + R[i] > mx)
     86             mx = i + R[i], id = i;
     87     }
     88 }
     89 
     90 int main()
     91 {
     92     scanf("%s", s);
     93     n = strlen(s);
     94     FFT_Prepare();
     95     for (char ch = 'a'; ch <= 'b'; ch ++)
     96         FFT_Work(ch);
     97     for (int i = 0; i < len; i ++)
     98     {
     99         T[i] = (T[i] + 1) >> 1;
    100         ans = Inc(ans, power(2, T[i], _Mod) - 1, _Mod);
    101     }
    102     Manacher();
    103     for (int i = 0; i <= (n << 1); i ++)
    104         ans = Inc(ans, _Mod - R[i] / 2, _Mod);
    105     printf("%d
    ", ans);
    106     
    107     return 0;
    108 }
    3160_Gromah
  • 相关阅读:
    Coursera机器学习week11 单元测试
    关于 TypeReference 的解释
    getModifiers 方法解释。
    instanceof isInstance isAssignableFrom 比较
    elasticsearch 基础 语法总结
    kibana 启动 关闭 和进程查找
    MD5 SHA1 SHA256 SHA512 SHA1WithRSA 的区别
    spring boot 项目 热启动
    java zip 压缩文件
    Packet for query is too large (1660 > 1024). You can change this value on the server by setting the max_allowed_packet' variable.
  • 原文地址:https://www.cnblogs.com/gromah/p/4652376.html
Copyright © 2020-2023  润新知