• luogu P4199 万径人踪灭


    嘟嘟嘟


    方案:回文子序列数 - 回文子串数。
    回文子串数用manacher解决就行了,关键是怎么求会问序列数。
    一个比较好的(O(n ^ 2))的算法:对于一个回文中心(i)(O(n))求出以(i)为中心位置对称且字母相同的字母对数(x),则以(i)为回文中心的回文子序列有(2 ^ x - 1)个(排除空序列)。
    现在想一下怎么优化。
    上面寻找的过程,用一个式子写出来就是这样:

    [c(i) = sum _ {j = 0} ^ {i} s[i - j] == s[i + j] ]

    会发现这东西和卷积特别像,但是怎么用多项式表示(s[i - j] == s[i + j])呢?
    因为题中说了只有(a, b)两种字母,所以构造两个只有(0)(1)的多项式(A, B),如果(s[i] = 'a'),那么(A(i) = 1)(B)同理。
    这样的话式子就变成了

    [c(i) = sum_{j = 0} ^ {i} A(i - j) * A(i + j) + sum _ {j = 0} ^ {i} B(i - j) * B(i + j) - 1 ]

    然后两次卷积就行啦。


    fft还是不熟……

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<stack>
    #include<queue>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define rg register
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const db PI = acos(-1);
    const int maxn = 8e5 + 5;
    const ll mod = 1e9 + 7;
    inline ll read()
    {
      ll ans = 0;
      char ch = getchar(), last = ' ';
      while(!isdigit(ch)) last = ch, ch = getchar();
      while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
      if(last == '-') ans = -ans;
      return ans;
    }
    inline void write(ll x)
    {
      if(x < 0) x = -x, putchar('-');
      if(x >= 10) write(x / 10);
      putchar(x % 10 + '0');
    }
    
    int n, len = 1;
    char s[maxn];
    
    struct Comp
    {
      db x, y;
      inline Comp operator + (const Comp& oth)const
      {
        return (Comp) {x + oth.x, y + oth.y};
      }
      inline Comp operator - (const Comp& oth)const
      {
        return (Comp){x - oth.x, y - oth.y};
      }
      inline Comp operator * (const Comp& oth)const
      {
        return (Comp){x * oth.x - y * oth.y, x * oth.y + oth.x * y};
      }
      friend inline void swap(Comp& a, Comp& b)
      {
        swap(a.x, b.x); swap(a.y, b.y);
      }
    }a[maxn], b[maxn], omg[maxn], inv[maxn];
    
    void init()
    {
      omg[0] = inv[0] = (Comp){1, 0};
      omg[1] = inv[len - 1] = (Comp){cos(2 * PI / len), sin(2 * PI / len)};
      for(int i = 2; i < len; ++i) omg[i] = inv[len - i] = omg[i - 1] * omg[1];
    }
    void fft(Comp* a, Comp* omg)
    {
      int lim = 0;
      while((1 << lim) < len) lim++;
      for(int i = 0; i < len; ++i)
        {
          int t = 0;
          for(int j = 0; j < lim; ++j) if((i >> j) & 1) t |= (1 << (lim - j - 1));
          if(i < t) swap(a[i], a[t]);
        }
      for(int l = 2; l <= len; l <<= 1)
        {
          int q = l >> 1;
          for(Comp* p = a; p != a + len; p += l)
    	for(int i = 0; i < q; ++i)
    	  {
    	    Comp t = omg[len / l * i] * p[i + q];
    	    p[i + q] = p[i] - t, p[i] = p[i] + t;
    	  }
        }
    }
    
    char t[maxn << 1];
    int p[maxn << 1], m;
    void manacher()
    {
      t[0] = '@';
      for(int i = 0; i < n; ++i) t[i << 1 | 1] = '#', t[(i << 1) + 2] = s[i];
      m = (n << 1) + 2;
      t[m - 1] = '#'; t[m] = '$'; 
      int mx = 0, id;
      for(int i = 1; i < m; ++i)
        {
          if(mx > i) p[i] = min(p[(id << 1) - i], mx - i);
          else p[i] = 1;
          while(t[i - p[i]] == t[i + p[i]]) p[i]++;
          if(i + p[i] > mx) mx = p[i] + i, id = i;
        }
    }
    
    ll quickpow(ll a, ll b)
    {
      ll ret = 1;
      for(; b; b >>= 1, a = a * a % mod)
        if(b & 1) ret = ret * a % mod;
      return ret;
    }
    
    ll Ans = 0;
    int ans[maxn];
    
    int main()
    {
      scanf("%s", s);
      n = strlen(s);
      while(len < (n << 1)) len <<= 1;
      for(int i = 0 ; i < n; ++i) a[i] = (Comp){s[i] == 'a', 0}, b[i] = (Comp){s[i] == 'b', 0};
      init();
      fft(a, omg); fft(b, omg);
      for(int i = 0; i < len; ++i) a[i] = a[i] * a[i] + b[i] * b[i];
      fft(a, inv);
      for(int i = 0; i < len; ++i) ans[i] = ((a[i].x / len + 0.5) + 1) / 2;
      for(int i = 0; i < len; ++i) Ans = (Ans + quickpow(2, ans[i]) - 1) % mod;
      manacher();
      for(int i = 1; i < m; ++i) Ans = (Ans - (p[i] >> 1) + mod) % mod;
      write(Ans), enter;
      return 0;
    }
    
  • 相关阅读:
    移动端页面制作字号大小设定问题,设计稿文字字号规范,解决移动端大小屏适配问题
    iPhone分辨率详细对比
    Flex 布局教程:语法篇
    带有可点击区域的图像映射(area)
    Stellar.js视差插件
    json中含有换行符' ',' '的处理
    windows下基于(QPC)实现的微秒级延时
    实现memcpy()函数及过程总结
    Welcome to MarkdownPad 2
    Cmake+Opencv+mingw+QT环境配置
  • 原文地址:https://www.cnblogs.com/mrclr/p/10095232.html
Copyright © 2020-2023  润新知