【做题】codechefCOUNTARI——分块FFT
记本题数组长度为\(n\),权值大小为\(m\)。
首先,暴力显然是\(O(n^2)\)的。
先瞄一眼tag,然后发现这是FFT。
显然,问题的关键在于要满足i,j,k之间的位置关系。于是考虑分治FFT。但遗憾的是,我们的分治FFT是对权值进行多项式乘法的,分治并不能使得FFT的规模减小。因此,分治做法在复杂度上就是错误的。
然后考虑分块。以下记块大小为\(K\)。
考虑一下三种情况:
- i,j在同一块中,但k在另一块里。
- j,k在同一块中,但i在另一块里。
- i,j,k都在同一块中。
- i,j,k都不在同一块中。
对于前三种情况,维护从1到每个块末端的权值的前缀和,用暴力就能解决。时间复杂度均为\(O(\frac {n}{K} \times K^2) = O(nK)\)。
对于最后一种情况,我们枚举j在哪一块,然后用FFT生成所有满足i在左边的块里,k在右边的块里的\(a_i+a_k\)的个数,利用\(2a_j=a_i+a_k\)就能统计出答案。这个的时间复杂度是\(O(\frac {n}{K} \times mlogm) < O(\frac {n^2logn}{K})\)。
那么有\(\frac {n^2logn}{K} + nK >= 2n^{\frac{3}{2}}log^{\frac{1}{2}}n\)。即复杂度为\(O(n^{\frac{3}{2}}log^{\frac{1}{2}}n)\)。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 200010, MAX = 200010;
typedef long double db;
const db pi = acos(-1);
struct cpl {
db x,y;
cpl(db x_=0,db y_=0): x(x_), y(y_) {};
cpl operator + (const cpl& a) const {
return cpl(x + a.x,y + a.y);
}
cpl operator - (const cpl& a) const {
return cpl(x - a.x,y - a.y);
}
cpl operator * (const cpl& a) const {
return cpl(x * a.x - y * a.y,x * a.y + y * a.x);
}
cpl operator * (const db& a) const {
return cpl(x * a,y * a);
}
};
cpl ta[MAX],tb[MAX];
int rev[MAX];
void prework(int n) {
rev[0] = 0;
for (int i = 1 ; i < n ; ++ i)
rev[i] = i&1 ? rev[i-1] | (n>>1) : rev[i>>1]>>1;
}
void fft(cpl* a,int n,int sgn) {
static cpl tmp[MAX];
for (int i = 0 ; i < n ; ++ i)
tmp[rev[i]] = a[i];
cpl wp,w,u,v;
for (int s = 2 ; s <= n ; s <<= 1) {
wp = cpl(cos(2 * pi / s),sin(2 * pi / s));
if (sgn) wp.y = -wp.y;
for (int k = 0 ; k < n ; k += s) {
w = cpl(1,0);
for (int j = 0 ; j < s/2 ; ++ j) {
u = tmp[k + j];
v = tmp[k + j + s/2] * w;
tmp[k + j] = u + v;
tmp[k + j + s/2] = u - v;
w = wp * w;
}
}
}
for (int i = 0 ; i < n ; ++ i)
a[i] = sgn ? tmp[i] * (1.0/n) : tmp[i];
}
const int SZ = 1500;
#define suit(x) ((x) >= 1 && (x) <= mx)
int bel[N],n,arr[N],tmp[N],cnt[N / SZ][MAX];
void solve() {
int mx = 0, ans = 0;
for (int i = 1 ; i <= n ; ++ i)
bel[i] = (i % SZ == 1 ? bel[i-1] + 1 : bel[i-1]);
for (int i = 1 ; i <= n ; ++ i) {
++ tmp[arr[i]];
mx = max(mx,arr[i]);
if (i % SZ == 0 || i == n) {
for (int j = 1 ; j <= mx ; ++ j)
cnt[bel[i]][j] = tmp[j];
}
}
int l = 1;
while (l < mx + mx + 1) l <<= 1;
prework(l);
for (int i = 2 ; i < bel[n] ; ++ i) {
for (int j = 0 ; j < l ; ++ j)
ta[j] = tb[j] = cpl();
for (int j = 1 ; j <= mx ; ++ j)
ta[j] = cpl(cnt[i-1][j],0);
for (int j = 1 ; j <= mx ; ++ j)
tb[j] = cpl(cnt[bel[n]][j] - cnt[i][j],0);
fft(ta,l,0);
fft(tb,l,0);
for (int j = 0 ; j < l ; ++ j)
ta[j] = ta[j] * tb[j];
fft(ta,l,1);
for (int j = 2 ; j <= mx * 2 ; j += 2)
tmp[j] = (int)(ta[j].x + 0.5);
for (int j = 1 ; j <= mx ; ++ j)
ans += tmp[j << 1] * (cnt[i][j] - cnt[i-1][j]);
}
for (int i = 1 ; i <= bel[n] ; ++ i) {
for (int j = (i-1) * SZ + 1 ; j <= i * SZ && j <= n ; ++ j)
for (int k = j + 1 ; k <= i * SZ && k <= n ; ++ k) {
if (suit(2 * arr[j] - arr[k]))
ans += cnt[i-1][2 * arr[j] - arr[k]];
if (suit(2 * arr[k] - arr[j]))
ans += cnt[bel[n]][2 * arr[k] - arr[j]] - cnt[i][2 * arr[k] - arr[j]];
}
}
memset(tmp,0,sizeof tmp);
for (int i = 1 ; i <= bel[n] ; ++ i) {
for (int j = (i-1) * SZ + 1 ; j <= i * SZ && j <= n ; ++ j) {
for (int k = j + 1 ; k <= i * SZ && k <= n ; ++ k) {
if ((!((arr[j] + arr[k]) & 1)) && suit((arr[j] + arr[k]) >> 1))
ans += tmp[(arr[j] + arr[k]) >> 1];
++ tmp[arr[k]];
}
for (int k = j + 1 ; k <= i * SZ && k <= n ; ++ k)
tmp[arr[k]] = 0;
}
}
printf("%lld\n",ans);
}
signed main() {
scanf("%lld",&n);
for (int i = 1 ; i <= n ; ++ i)
scanf("%lld",&arr[i]);
solve();
return 0;
}
小结:这种难以用分治减小规模的问题,不妨用分块来简化。
【做题】codechefCOUNTARI——分块FFT的更多相关文章
- [日记&做题记录]-Noip2016提高组复赛 倒数十天
写这篇博客的时候有点激动 为了让自己不颓 还是写写日记 存存模板 Nov.8 2016 今天早上买了两个蛋挞 吃了一个 然后就做数论(前天晚上还是想放弃数论 但是昨天被数论虐了 woc noip模拟赛 ...
- project euler做题记录
ProjectEuler_做题记录 简单记录一下. problem 441 The inverse summation of coprime couples 神仙题.考虑答案为: \[\begin{a ...
- AtCoder Grand Contest 1~10 做题小记
原文链接https://www.cnblogs.com/zhouzhendong/p/AtCoder-Grand-Contest-from-1-to-10.html 考虑到博客内容较多,编辑不方便的情 ...
- BZOJ做题记录[0512~?]
觉得做一道开一篇真不好...好多想找的东西都被刷下去了... 至于?的日期究竟到什么时候...还是看心情...但是估计不会超过七天吧 最后更新时间:05/19 10:42 [05/14 10:56]我 ...
- BZOJ 3509 分块FFT
思路: 跟今年WC的题几乎一样 (但是这道题有重 不能用bitset水过去) 正解:分块FFT http://blog.csdn.net/geotcbrl/article/details/506364 ...
- PKUWC/SC 做题笔记
去年不知道干了些啥,什么省选/营题都没做. 现在赶应该还来得及(?) 「PKUWC2018」Minimax Done 2019.12.04 9:38:55 线段树合并船新玩法??? \(O(n^2)\ ...
- UOJ 做题记录
UOJ 做题记录 其实我这么弱> >根本不会做题呢> > #21. [UR #1]缩进优化 其实想想还是一道非常丝播的题目呢> > 直接对于每个缩进长度统计一遍就好 ...
- C语言程序设计做题笔记之C语言基础知识(下)
C 语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行 事.并且C是相当灵活的,用于执行计算机程序能完成的 ...
- C语言程序设计做题笔记之C语言基础知识(上)
C语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行事.并且C是相当灵活的,用于执行计算机程序能完成的几乎 ...
随机推荐
- 将网站项目转为 Web form应用程序(转)
转自 http://blog.sina.com.cn/s/blog_53729e4601014ze9.html 本文介绍如何将现有的 Microsoft Visual Studio 2005 网站项目 ...
- 检索系统向量化计算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 ...
- ubuntu安装启动redis
1.下载安装 sudo apt-get install build-essential wget http://redis.googlecode.com/files/redis-2.2.13.ta ...
- CSS position &居中(水平,垂直)
css position是个很重要的知识点: 知乎Header部分: 知乎Header-inner部分: position属性值: fixed:生成绝对定位的元素,相对浏览器窗口进行定位(位置可通过: ...
- sitecore系列教程之Sitecore个性化-试点开始,测试,优化,增量
这是利用Sitecore的个性化引擎实现数字化转型的三部分系列的第三部分.之前的帖子旨在通过为您的个性化体验定义内容策略并在Sitecore中配置该策略来设置基础. 在此之前,我们讨论了内容策略以 ...
- jQuery筛选--first()和last()
first() 概述 获取匹配的第一个元素 last() 概述 获取匹配的最后个元素 <!DOCTYPE html> <html> <head> < ...
- 【Hbase学习之三】Hbase Java API
环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 jdk8 hadoop-2.6.5 hbase-0.98.12.1-h ...
- Log4j基础知识
Log4J是Apache的一个开放源代码的项目.通过使用Log4J,程序员可以控制日志信息输送的目的地,包括控制台,文件,GUI组件和NT事件记录器,也可以控制每一条日志的输出格式,或通过定义每一条日 ...
- java初学者必看的学习路线
不管在编程语言的排行榜中,还是在大多数企业应用的广泛程度来看,Java一直都是当之无愧的榜首.Java语言有着独特的魅力吸引着广大的年轻人去学习,每个人学习的方式方法不一样. 第一步:首先要做好学习前 ...
- Python笔记 #20# SOM
SOM(自组织映射神经网络)是一种可以根据输入对象的特征自动进行分类(聚类)的神经网络.向该网络输入任意维度的向量都会得到一个二维图像, 不同特征的输入会被映射到二维图像的不同地方(所以SOM也可以用 ...