记本题数组长度为\(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的更多相关文章

  1. [日记&做题记录]-Noip2016提高组复赛 倒数十天

    写这篇博客的时候有点激动 为了让自己不颓 还是写写日记 存存模板 Nov.8 2016 今天早上买了两个蛋挞 吃了一个 然后就做数论(前天晚上还是想放弃数论 但是昨天被数论虐了 woc noip模拟赛 ...

  2. project euler做题记录

    ProjectEuler_做题记录 简单记录一下. problem 441 The inverse summation of coprime couples 神仙题.考虑答案为: \[\begin{a ...

  3. AtCoder Grand Contest 1~10 做题小记

    原文链接https://www.cnblogs.com/zhouzhendong/p/AtCoder-Grand-Contest-from-1-to-10.html 考虑到博客内容较多,编辑不方便的情 ...

  4. BZOJ做题记录[0512~?]

    觉得做一道开一篇真不好...好多想找的东西都被刷下去了... 至于?的日期究竟到什么时候...还是看心情...但是估计不会超过七天吧 最后更新时间:05/19 10:42 [05/14 10:56]我 ...

  5. BZOJ 3509 分块FFT

    思路: 跟今年WC的题几乎一样 (但是这道题有重 不能用bitset水过去) 正解:分块FFT http://blog.csdn.net/geotcbrl/article/details/506364 ...

  6. PKUWC/SC 做题笔记

    去年不知道干了些啥,什么省选/营题都没做. 现在赶应该还来得及(?) 「PKUWC2018」Minimax Done 2019.12.04 9:38:55 线段树合并船新玩法??? \(O(n^2)\ ...

  7. UOJ 做题记录

    UOJ 做题记录 其实我这么弱> >根本不会做题呢> > #21. [UR #1]缩进优化 其实想想还是一道非常丝播的题目呢> > 直接对于每个缩进长度统计一遍就好 ...

  8. C语言程序设计做题笔记之C语言基础知识(下)

    C 语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行 事.并且C是相当灵活的,用于执行计算机程序能完成的 ...

  9. C语言程序设计做题笔记之C语言基础知识(上)

    C语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行事.并且C是相当灵活的,用于执行计算机程序能完成的几乎 ...

随机推荐

  1. Python 1.安装

    Python是一种开源语言,有很多第三方库. 1. Python3 及相关组件下载及安装 a. Python3下载:https://www.python.org/downloads/->点击以下 ...

  2. 20155228 2017-5-10 课堂测试:MySort

    20155228 2017-5-10 课堂测试:MySort 题目和要求 模拟实现Linux下Sort-t:-k2的功能.参考Sort的实现.提交码云链接和代码运行截图. import java.ut ...

  3. 【2017-03-21】HTML表单及标记

    一.表单 表单在网页中主要负责数据采集功能 表单格式 <form action="服务器路径" method=get(用的比较少)/post(最常用)></for ...

  4. hashcat 中文文档

    hashcat   描述 hashcat是世界上最快,最先进的密码恢复工具. 此版本结合了以前基于CPU的hashcat(现在称为hashcat-legacy)和基于GPU的oclHashcat. H ...

  5. Hive分区表新增字段及修改表名,列名,列注释,表注释,增加列,调整列顺序,属性名等操作

    一.Hive分区表新增字段 参考博客:https://blog.csdn.net/yeweiouyang/article/details/44851459 二.Hive修改表名,列名,列注释,表注释, ...

  6. SQL小结

    1. 一般而言,除非你确实需要表中的每一列,否则最好别使用*通配符.虽然使用通配符让你自己省事,不用明确列出所需列,但检索不需要的列通常会降低检索和应用程序的性能. 2. DISTINCT关键字作用于 ...

  7. 囤币一族,被中国市场遗忘的价值币ADA

    囤币一族,被中国市场遗忘的价值币ADA ==========================长期囤币目标:trx十万个,ada一万个,eos五千个,nas一千个,ont一千个,eth一百个,比特币十个 ...

  8. 安装PG3.0详细教程附图

    从公司要求开始着手调研PG到今天上午都还不知道如何安装PG.. 囧的离谱.. 看了半天的PG官网 就这个网页我瞅了半天..对你没看错 半天 少说有10分钟..原谅我的英文不是非常好..但是我知道什么意 ...

  9. How to use CAR FANS C800 Diagnostic Scan Tool to do diagnosis operation

    How to use Heavy Duty Diagnostic CAR FANS C800 Diagnostic Scan Tool to do diagnosis operation Here i ...

  10. 自学Java第五周的总结

    在这周里我在我要自学网上观看视频学习了有关java的基础知识,课程主要介绍JavaSE,这是整个Java体系的基础:课程将由浅入深,并结合案例进行讲解,在那里我将自己已学的知识进行了巩固,并由学习到了 ...