zoukankan      html  css  js  c++  java
  • BZOJ 3160 万径人踪灭

    题面

    题面
    题面
    题面

    题目大意

    略.

    题解

    FFT跑一遍, 由于不能连续, 因此再跑一次manacher减去不符合题意的部分.
    这道题体现了FFT的一种用途: 在序列中元素个数不多的情况下, 找关于某个中心对称的相同字符.

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <cstdlib>
    
    const int N = (int)1e5, MOD = (int)1e9 + 7;
    
    namespace convolution
    {
    	struct complex
    	{
    		double rl, img;
    
    		inline complex() {}
    
    		inline complex(double _rl, double _img)
    		{
    			rl = _rl, img = _img;
    		}
    
    		inline complex friend operator +(complex a, complex b)
    		{
    			return complex(a.rl + b.rl, a.img + b.img);
    		}
    
    		inline complex friend operator -(complex a, complex b)
    		{
    			return complex(a.rl - b.rl, a.img - b.img);
    		}
    
    		inline complex friend operator *(complex a, complex b)
    		{
    			return complex(a.rl * b.rl - a.img * b.img, a.rl * b.img + b.rl * a.img);
    		}
    	}A[N << 2], B[N << 2];
    
    	int len;
    	int rev[N << 2];
    
    	inline void initialize(int n)
    	{
    		len = 1;
    		int tmp = 0;
    		for(; len < n << 1; len <<= 1, ++ tmp);
    		rev[0] = 0;
    		for(int i = 1; i < len; ++ i)
    			rev[i] = rev[i >> 1] >> 1 | (i & 1) << (tmp - 1);
    	}
    
    	double PI = acos(-1);
    
    	inline void FFT(complex *a, int opt)
    	{
    		for(int i = 0; i < len; ++ i)
    			if(rev[i] < i)
    				std::swap(a[i], a[rev[i]]);
    		for(int i = 2; i <= len; i <<= 1)
    		{
    			complex omg_i = complex(cos(2 * PI * opt / i), sin(2 * PI * opt / i));
    			for(int j = 0; j < len; j += i)
    			{
    				complex omg = complex(1, 0);
    				for(int k = j; k < j + i / 2; ++ k)
    				{
    					complex u = a[k], t = omg * a[k + i / 2];
    					a[k] = u + t, a[k + i / 2] = u - t;
    					omg = omg * omg_i;
    				}
    			}
    		}
    		if(opt == -1)
    			for(int i = 0; i < len; ++ i)
    				a[i].rl /= len;
    	}
    
    	inline void work(int *a, int *b, int n, int *res)
    	{
    		initialize(n);
    		memset(A, 0, sizeof(A)), memset(B, 0, sizeof(B));
    		for(int i = 0; i < n; ++ i)
    			A[i] = complex(a[i], 0);
    		for(int i = 0; i < n; ++ i)
    			B[i] = complex(b[i], 0);
    		FFT(A, 1), FFT(B, 1);
    		for(int i = 0; i < len; ++ i)
    			A[i] = A[i] * B[i];
    		FFT(A, -1);
    		memset(res, 0, sizeof(res));
    		for(int i = 0; i < len; ++ i)
    			res[i] = round(A[i].rl);
    	}
    }
    
    int pw[N << 1];
    
    inline void getPower()
    {
    	pw[0] = 1;
    	for(int i = 1; i < N << 2; ++ i)
    		pw[i] = (long long)pw[i - 1] * 2 % MOD;
    }
    
    namespace manacher
    {
    	int a[N << 1 | 1], p[N << 1 | 1];
    
    	inline int work(char *str, int len)
    	{
    		memset(a, 0, sizeof(a));
    		a[0] = '#';
    		for(int i = 0; i < len; ++ i)
    			a[i << 1 | 1] = str[i], a[i + 1 << 1] = '#';
    		a[len + 1 << 1] = '#';
    		len = len << 1 | 1;
    		int mx = 0, id = 0;
    		for(int i = 0; i < len; ++ i)
    		{
    			p[i] = mx > i ? std::min(mx - i, p[(id << 1) - i]) : 1;
    			for(; i >= p[i] && i + p[i] < len && a[i - p[i]] == a[i + p[i]]; ++ p[i]);
    			if(p[i] + i > mx)
    				mx = p[i] + i, id = i;
    		}
    		int ans = 0;
    		for(int i = 0; i < len; ++ i)
    			ans = (ans + (p[i] >> 1)) % MOD;
    		return ans;
    	}
    }
    
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("BZOJ3160.in", "r", stdin);
    	freopen("BZOJ3160.out", "w", stdout);
    	#endif
    	static char str[N];
    	scanf("%s", str);
    	int n = strlen(str);
    	static int a[N];
    	static int res1[N << 2], res2[N << 2], res[N << 2];
    	memset(a, 0, sizeof(a));
    	for(int i = 0; i < n; ++ i)
    		a[i] = str[i] == 'a';
    	convolution::work(a, a, n, res1);
    	memset(a, 0, sizeof(a));
    	for(int i = 0; i < n; ++ i)
    		a[i] = str[i] == 'b';
    	convolution::work(a, a, n, res2);
    	for(int i = 0; i < n << 1; ++ i)
    		res[i] = res1[i] + res2[i] + 1 >> 1;
    	getPower();
    	int ans = 0;
    	for(int i = 0; i < n << 1; ++ i)
    		ans = (ans + pw[res[i]] - 1) % MOD;
    	printf("%d
    ", (ans - manacher::work(str, n) + MOD) % MOD);
    }
    
    
  • 相关阅读:
    PHP cURL 函数
    PHP 5 Calendar 函数
    PHP 5 Array 函数
    PHP 实例 AJAX 投票
    PHP 实例 AJAX RSS 阅读器
    PHP 实例
    PHP 实例 AJAX 与 XML
    PHP 实例 AJAX 与 MySQL
    22_传智播客iOS视频教程_类的定义
    21_传智播客iOS视频教程_类的设计和名词提炼法
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/7106813.html
Copyright © 2011-2022 走看看