Codeforces 827E Rusty String - 快速傅里叶变换 - 暴力
Grigory loves strings. Recently he found a metal strip on a loft. The strip had length n and consisted of letters "V" and "K". Unfortunately, rust has eaten some of the letters so that it's now impossible to understand which letter was written.
Grigory couldn't understand for a long time what these letters remind him of, so he became interested in the following question: if we put a letter "V" or "K" on each unreadable position, which values can the period of the resulting string be equal to?
A period of a string is such an integer d from 1 to the length of the string that if we put the string shifted by d positions to the right on itself, then all overlapping letters coincide. For example, 3 and 5 are periods of "VKKVK".
There are several (at least one) test cases in the input. The first line contains single integer — the number of test cases.
There is an empty line before each test case. Each test case is described in two lines: the first line contains single integer n(1 ≤ n ≤ 5·105) — the length of the string, the second line contains the string of length n, consisting of letters "V", "K" and characters "?". The latter means the letter on its position is unreadable.
It is guaranteed that the sum of lengths among all test cases doesn't exceed 5·105.
For hacks you can only use tests with one test case.
For each test case print two lines. In the first line print the number of possible periods after we replace each unreadable letter with "V" or "K". In the next line print all these values in increasing order.
3
5
V??VK
6
??????
4
?VK?
2
3 5
6
1 2 3 4 5 6
3
2 3 4
In the first test case from example we can obtain, for example, "VKKVK", which has periods 3 and 5.
In the second test case we can obtain "VVVVVV" which has all periods from 1 to 6.
In the third test case string "KVKV" has periods 2 and 4, and string "KVKK" has periods 3 and 4.
题目大意 给定一个只包含通配符'?'和'v','K'的串,询问所有可能的循环节长度。
首先一个事实就是如果x是可能的循环节,那么2x,3x也一定是。(证明是显然的)
因此可以根据这个愉快的事实进行暴力(似乎出题人在题解的Comments中表示对数据出水了感到歉意)
思路大概就是暴力check如果可行就把它的倍数都标为可行的。
Code
/**
* Codeforces
* Problem#827E
* Accepted
* Time: 265ms
* Memory: 988k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; const int lim = 5e5; int n;
char str[lim + ];
boolean app[];
boolean able[lim + ]; inline void init() {
scanf("%d", &n);
gets(str);
gets(str);
} inline boolean check(int len) {
for(int i = ; i < len; i++) {
char should = str[i];
for(int j = i + len; j < n; j += len) {
if(should != '?' && str[j] != '?' && should != str[j]) return false;
if(str[j] != '?') should = str[j];
}
}
return true;
} inline void solve() {
app[] = app[] = false;
for(int i = ; i < n; i++) {
switch(str[i]) {
case 'V':
app[] = true;
break;
case 'K':
app[] = true;
break;
}
}
if(!app[] && !app[]) {
printf("%d\n", n);
for(int i = ; i <= n; i++)
printf("%d%c", i, (i == n) ? ('\n') : (' '));
return;
}
int res = ; //, cnt = 0;
for(int i = ; i <= n; i++)
if(!able[i] && check(i))// && (++cnt))
for(int j = i; j <= n; j += i)
res += !able[j], able[j] = true;
printf("%d\n", res);
for(int i = ; i <= n; i++)
if(able[i]) {
printf("%d ", i);
able[i] = false;
}
putchar('\n');
// fprintf(stderr, "%dms counted %d times\n", clock(), cnt);
} int T;
int main() {
scanf("%d", &T);
while(T--) {
init();
solve();
}
return ;
}
Rusty String(Brute force)
然后假设没有这个通配符应该怎么用bitset, 多项式乘法之类的做(因为每个位置除了通配符,只有V或K,而且因为有通配符的存在,所以KMP就不能抓过来用了)
首先根据KMP的思想,如果存在长度为k的循环节那么存在长度为(n - k)的公共前后缀。
所以我们可以把这个串右移k位然后check,最后判一下特殊情况。
为了更快地进行check,所以,我们设A数组中A[I]为1当且仅当s[I] == 'v',B[i]为1当且仅当s[i] == 'K'。
初步可行的条件是
并且
然后为了能够顺利地进行下一步,我们设A'[i] = A[n - i - 1]。于是你会发现两边A'的下标和B的和是一个定值,而且范围不相交。因此我们可以把A'数组和B数组当成两个多项式的系数数组,然后进行FFT。
最开始说的特殊情况是指类似于存在某一个i使得s[i] != s[i + 2k]并且s[i + k] == '?'。
首先可以初步地将一些循环节判断为不可行,对于看似没有问题的循环节长度,我们还需要check它的倍数中有没有被标记为不可行的,如果存在它就不可行(这样做的话就可以把以上的特殊情况处理掉)。
因为数据没有卡暴力,我深深地感受到什么是暴力碾压正解。
Code
/**
* Codeforces
* Problem#827
* Accepted
* Time: 311ms
* Memory: 68200k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; template<typename T>
class Complex {
public:
T r;
T v; Complex(T r = , T v = ):r(r), v(v) { } Complex operator + (Complex b) {
return Complex(r + b.r, v + b.v);
} Complex operator - (Complex b) {
return Complex(r - b.r, v - b.v);
} Complex operator * (Complex b) {
return Complex(r * b.r - v * b.v, r * b.v + v * b.r);
} Complex operator / (double x) {
return Complex(r / x, v / x);
}
}; const int N = << ;
const double pi = acos(-);
const double eps = 0.5; inline void Rader(Complex<double> *f, int len) {
for(int i = , j = len >> , k; i < len - ; i++) {
if(i < j)
swap(f[i], f[j]);
for(k = len >> ; j >= k; j -= k, k >>= );
if(j < k)
j += k;
}
} inline void fft(Complex<double> *f, int len, int sign) {
Rader(f, len);
for(int l = ; l <= len; l <<= ) {
Complex<double> wn(cos( * pi / l), sin( * pi * sign / l)), u, v;
int hl = l >> ;
for(int i = ; i < len; i += l) {
Complex<double> w(, );
for(int j = ; j < hl; j++, w = w * wn) {
u = f[i + j], v = w * f[i + j + hl];
f[i + j] = u + v, f[i + j + hl] = u - v;
}
}
}
if(sign == -)
for(int i = ; i < len; i++)
f[i] = f[i] / len;
} int n, len;
char str[];
Complex<double> A[N], B[N]; inline void init() {
scanf("%d", &n);
gets(str);
gets(str);
for(len = ; len < (n << ); len <<= );
memset(A, , sizeof(Complex<double>) * (len + ));
memset(B, , sizeof(Complex<double>) * (len + ));
for(int i = ; i < n; i++) {
if(str[i] == 'V')
A[n - i - ].r = ;
else if(str[i] == 'K')
B[i].r = ;
}
} boolean bad[N];
int res = ;
inline void solve() {
fft(A, len, );
fft(B, len, );
for(int i = ; i < len; i++) A[i] = A[i] * B[i];
fft(A, len, -);
memset(bad, false, sizeof(boolean) * (n + ));
// for(int i = 1; i < n; i++)
// if(A[n - i - 1].r >= eps || A[n + i - 1].r >= eps)
// bad[i] = true;
for(int i = ; i < len; i++)
if(A[i].r >= eps)
bad[abs(i - n + )] = true;
for(int i = ; i < n; i++)
if(!bad[i])
for(int j = i << ; j < n; j += i)
if(bad[j]) {
bad[i] = true;
break;
}
int res = ;
for(int i = ; i <= n; i++)
if(!bad[i])
res++;
printf("%d\n", res);
for(int i = ; i <= n; i++) {
if(!bad[i])
printf("%d ", i);
}
putchar('\n');
} int T;
int main() {
scanf("%d", &T);
while(T--) {
init();
solve();
}
return ;
}
Codeforces 827E Rusty String - 快速傅里叶变换 - 暴力的更多相关文章
- CF 827E Rusty String FFT
传送门 如果没有碍事的?的话,判定字符串的循环节直接用KMP的失配数组就可以搞定.现在有了碍事的?,我们就需要考虑更通用的算法. 考虑KMP失配数组判定字符串循环节的本质,发现判定\(k\)是否为字符 ...
- 多项式 之 快速傅里叶变换(FFT)/数论变换(NTT)/常用套路【入门】
原文链接https://www.cnblogs.com/zhouzhendong/p/Fast-Fourier-Transform.html 多项式 之 快速傅里叶变换(FFT)/数论变换(NTT)/ ...
- 【知识总结】快速傅里叶变换(FFT)
这可能是我第五次学FFT了--菜哭qwq 先给出一些个人认为非常优秀的参考资料: 一小时学会快速傅里叶变换(Fast Fourier Transform) - 知乎 小学生都能看懂的FFT!!! - ...
- 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT)
再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT) 目录 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Blueste ...
- 快速傅里叶变换FFT& 数论变换NTT
相关知识 时间域上的函数f(t)经过傅里叶变换(Fourier Transform)变成频率域上的F(w),也就是用一些不同频率正弦曲线的加 权叠加得到时间域上的信号. \[ F(\omega)=\m ...
- 快速傅里叶变换(FFT)
扯 去北京学习的时候才系统的学习了一下卷积,当时整理了这个笔记的大部分.后来就一直放着忘了写完.直到今天都腊月二十八了,才想起来还有个FFT的笔记没整完呢.整理完这个我就假装今年的任务全都over了吧 ...
- 51Nod 快速傅里叶变换题集选刷
打开51Nod全部问题页面,在右边题目分类中找到快速傅里叶变换,然后按分值排序,就是本文的题目顺序. 1.大数乘法问题 这个……板子就算了吧. 2.美妙的序列问题 长度为n的排列,且满足从中间任意位置 ...
- 快速傅里叶变换FFT / NTT
目录 FFT 系数表示法 点值表示法 复数 DFT(离散傅里叶变换) 单位根的性质 FFT(快速傅里叶变换) IFFT(快速傅里叶逆变换) NTT 阶 原根 扩展知识 FFT 参考blog: 十分简明 ...
- 快速傅里叶变换(FFT)相关内容汇总
(原稿:https://paste.ubuntu.com/p/yJNsn3xPt8/) 快速傅里叶变换,是求两个多项式卷积的算法,其时间复杂度为$O(n\log n)$,优于普通卷积求法,且根据有关证 ...
随机推荐
- cocos2d JS-(JavaScript) 基础语法间的函数方法相互调用
1.函数嵌套函数 function calcuate(opr, a, b) { // 定义函数,opr - -> 符号,a,b - -> 数值 //定义 + 函数 function add ...
- python对字典及列表递归排序
对字典内所有内容进行排升序排序,包括,子数组,子字典 需要注意: 1.字典因为是在一定程序上无序的,所以这里采用了内置包,来变成有序字典 from collections import Ordered ...
- obv15 实例6:如果K线柱过多,ZIG将发生变动,导致明显的OBV15指标被隐藏!
obv
- Ubuntu 16.04卸载一些不必要的预装软件
卸载libreoffices ~$ sudo apt-get remove libreoffice-common 卸载Amazon的链接 ~$ sudo apt-get remove unity-we ...
- DW表格的简单应用 之(个人简历模板)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 检索系统向量化计算query-doc相似度
def cal_sim2(A,B): ''' A :query [1,2] B: answers [[1,2],[3,5]] ''' need_norm=False A = np.array(A) B ...
- 对象的copy
一般来讲,java中,对象的copy一般是通过Beans.copy(B, A);用来将A对象复制给B对象,包括对象里面的属性和值. 但但但...... 这样做,有一个很严重的问题,那就是:如果把A对象 ...
- Vim for Windows --ctags
What is ctags? ctags -- Generate tag files for source code,which is a tool used for facilitating rea ...
- Gamma函数深入理解
Gamma函数 当n为正整数时,n的阶乘定义如下:n! = n * (n - 1) * (n - 2) * … * 2 * 1. 当n不是整数时,n!为多少?我们先给出答案. 容易证明,Γ(x + 1 ...
- 利用可排序Key-Value DB构建时间序列数据库(简论)
为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处.LaplaceDemon/ShiJiaqi. http://www.cnblogs.com/shijiaqi1066/p/5855064. ...