【HDU5751 BestCoder Round 84E】【FFT + 线段树求最值】Eades 最大数出现次数为[1~n]的区间个数
来源:互联网 发布:搜索关键词淘宝 编辑:程序博客网 时间:2024/05/16 00:59
Eades
Accepts: 1
Submissions: 11
Time Limit: 12000/6000 MS (Java/Others)
Memory Limit: 131072/131072 K (Java/Others)
问题描述
Peter有一个序列a1,a2,...,an. 定义g(l,r)表示子序列al,al+1,...,ar的最大值, f(l,r)=i=l∑r[ai=g(l,r)]. 注意[condition]=1当且仅当condition是true, 否则[condition]=0.对于每个整数k∈{1,2,...,n}, Peter想要知道有多少整数对l和r (l≤r)满足f(l,r)=k.
输入描述
输入包含多组数据, 第一行包含一个整数T表示测试数据组数. 对于每组数据:第一行包含一个整数n (1≤n≤60000)表示序列的长度. 第二行包含n个整数a1,a2,...,an (1≤ai≤n).
输出描述
对于每组数据, 输出一个整数S=k=1∑nk⊕zk, 其中zk表示满足f(l,r)=k的数对l和r的个数, ⊕是异或位运算操作.
输入样例
331 2 341 1 1 161 2 2 1 1 2
输出样例
121236
#include<stdio.h>#include<iostream>#include<string.h>#include<string>#include<ctype.h>#include<math.h>#include<set>#include<map>#include<vector>#include<queue>#include<bitset>#include<algorithm>#include<time.h>using namespace std;void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }#define MS(x,y) memset(x,y,sizeof(x))#define MC(x,y) memcpy(x,y,sizeof(x))#define MP(x,y) make_pair(x,y)#define ls o<<1#define rs o<<1|1#define lson o<<1,l,mid#define rson o<<1|1,mid+1,rtypedef long long LL;typedef unsigned long long UL;typedef unsigned int UI;template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }const int N = 60010, M = 0, Z = 1e9 + 7, ms63 = 0x3f3f3f3f;int casenum, casei;int n;int a[N];vector<int>p[N];int mx[1 << 17];LL ans[N];void build(int o, int l, int r){ if (l == r) { mx[o] = a[l]; return; } int mid = (l + r) >> 1; build(lson); build(rson); mx[o] = max(mx[ls], mx[rs]);}int getmx(int o, int l, int r, int L, int R){ if (l >= L&&r <= R)return mx[o]; int mid = (l + r) >> 1; int ret = 0; if (L <= mid)gmax(ret, getmx(lson, L, R)); if (R > mid)gmax(ret, getmx(rson, L, R)); return ret;}const double PI = acos(-1.0);struct Complex{ double r, i; Complex(double r = 0, double i = 0) : r(r), i(i) {} Complex operator + (const Complex& t) const { return Complex(r + t.r, i + t.i); } Complex operator - (const Complex& t) const { return Complex(r - t.r, i - t.i); } Complex operator * (const Complex& t) const { return Complex(r * t.r - i * t.i, r * t.i + i * t.r); }}X[1 << 17], Y[1 << 17];void FFT(Complex y[], int n, int rev)//rev == 1时为DFT,rev == -1时为IDFT{ for (int i = 1, j, k, t; i < n; ++i) { for (j = 0, k = n >> 1, t = i; k; k >>= 1, t >>= 1) j = j << 1 | t & 1; if (i < j) swap(y[i], y[j]); } for (int s = 2, ds = 1; s <= n; ds = s, s <<= 1) { Complex wn(cos(rev * 2 * PI / s), sin(rev * 2 * PI / s)); for (int k = 0; k < n; k += s) { Complex w(1, 0), t; for (int i = k; i < k + ds; ++i) { y[i + ds] = y[i] - (t = w * y[i + ds]); y[i] = y[i] + t; w = w * wn; } } } if (rev == -1) for (int i = 0; i < n; ++i) y[i].r /= n;}void solve(int l, int r){ if (l > r)return; if (l == r) { ++ans[1]; return; } int v = getmx(1, 1, n, l, r); int lft = lower_bound(p[v].begin(), p[v].end(), l) - p[v].begin(); int rgt = upper_bound(p[v].begin(), p[v].end(), r) - p[v].begin() - 1; vector<int>pos; pos.push_back(l - 1); for (int i = lft; i <= rgt; ++i)pos.push_back(p[v][i]); pos.push_back(r + 1); int num = rgt - lft + 2; for (int i = 0; i < num; ++i)X[i] = { (double)pos[i + 1] - pos[i], 0 }; for (int i = 0; i < num; ++i)Y[i] = X[num - 1 - i]; int len = 1; while (len < num + num)len <<= 1; for (int i = num; i < len; ++i)X[i] = Y[i] = { 0,0 }; FFT(X, len, 1); FFT(Y, len, 1); for (int i = 0; i < len; ++i)Y[i] = X[i] * Y[i]; FFT(Y, len, -1); for (int i = 0; i < num - 1; ++i)ans[num - 1 - i] += (Y[i].r + 0.5); for (int i = 0; i < num; ++i) { solve(pos[i] + 1, pos[i + 1] - 1); }}int main(){ scanf("%d", &casenum); for (casei = 1; casei <= casenum; ++casei) { scanf("%d", &n); for (int i = 1; i <= n; ++i) { p[i].clear(); ans[i] = 0; } for (int i = 1; i <= n; ++i) { scanf("%d", &a[i]); p[a[i]].push_back(i); } build(1, 1, n); solve(1, n); LL ANS = 0; for (int i = 1; i <= n; ++i)ANS += ans[i] ^ i; printf("%lld\n", ANS); } return 0;}/*【trick&&吐槽】1,注意尽量不要让全局变量数组设计迭代,会重复共享而出错的!2,注意FFT的len要从1开始倍增,这样才保证其为2的幂次【题意】有一个长度为n(60000)的序列a[]。我们想要知道——有多少个区间最大值数的出现数量恰好为k次(k∈[1,n])输出:∑(ans[k]^k) k ∈[1,n]【类型】线段树 + fft【分析】这道题,我们首先思考枚举最大值(这个思路很常见,因为一共只有n个最大值,同时,我们在知道最大值的条件下,更容易算出其对答案的贡献)我们如何求出最大值呢?可以写一棵线段树实现。我们知道最大值之后,如何算出有多少个区间包含这个最大值呢?我们可以通过查询出所有最大值点来实现。具体而言,就是,我们把权值为x的所有数,都push_back入p[x]的vector中,存一下权值为x的数的所有位置。然后进入一个solve(l, r)的递归函数所谓solve(l, r),就是——在区间边界不能<l 且 不能 >r(即区间左右界被局限在[l,r]范围内,否则就会打破最大值限制)的条件下,我们思考该区间内部的最大值,对答案的贡献。用线段树可以求出该区间的最大值,设为v然后通过二分查找,查询出在[l,r]范围内,权值为v的所有数。接下来,我们发现,对于ans[k],我们就要找到该区间范围内第i个v,和第i+k-1个v,然后——假设i左侧有lft个可以不延展到v[i-1]的位点假设i+k-1右侧有rgt个可以不延展到v[i+k]的位点,那么,对于ans[k],我们就获得了lft*rgt的答案贡献。然而,我们不能暴力算,暴力算的复杂度为O(n^2)我们需要借助fft的力量。我们求出,每个区间最大值的点,在不延展到前一个区间最大值点的条件下,其可以向左延展多少个数,记做c[]显然,在我们求出区间内的所有数之后,比如区间内,p[v][lft]~p[v][rgt]都是权值为v的点位那么c[0]=p[v][lft]-l+1,c[num]=r-p[v][rgt]+1,c[i]=p[v][x]-p[v][x-1]那么,对于ans[k],我们所获得的贡献是∑c[i]*c[i+k]。而这个所对应的,就相当于是卷积FFT。c[0] c[1] c[2] c[3] c[4]c[0] c[1] c[2] c[3] c[4]它们做FFT之后,我们可以得到——(c[0] * c[0])(c[0] * c[1] + c[1] * c[0])(c[0] * c[2] + c[1] * c[1] + c[2] *c[1])(c[0] * c[3] + c[1] * c[2] + c[2] * c[1] + c[3] * c[0])(c[0] * c[4] + c[1] * c[3] + c[2] * c[2] + c[3] * c[1] + c[4] * c[0])(c[1] * c[4] + c[2] * c[3] + c[3] * c[2] + c[4] * c[1])(c[2] * c[4] + c[3] * c[3] + c[4] * c[2])(c[3] * c[4] + c[4] * c[3])(c[4] * c[4])做一下对称反转c[0] c[1] c[2] c[3] c[4]c[4] c[3] c[2] c[1] c[0]它们做FFT之后,我们可以得到——(c[0] * c[4]) ->ans[4](c[0] * c[3] + c[1] * c[4]) ->ans[3](c[0] * c[2] + c[1] * c[3] + c[2] *c[4]) ->ans[2](c[0] * c[1] + c[1] * c[2] + c[2] * c[3] + c[3] * c[4]) ->ans[1](c[0] * c[0] + c[1] * c[1] + c[2] * c[2] + c[3] * c[3] + c[4] * c[4])(c[1] * c[0] + c[2] * c[1] + c[3] * c[2] + c[4] * c[3]) ->ans[1](c[2] * c[0] + c[3] * c[1] + c[4] * c[2]) ->ans[2](c[3] * c[0] + c[4] * c[1]) ->ans[3](c[4] * c[0]) ->ans[4]也就生成了对ans[4],ans[3],ans[2],ans[1]...的贡献。(我们只要拿一半统计、计数即可)【时间复杂度&&优化】O(nlogn)复杂度如何算呢?每个点最多参与一次fft,所以复杂度大概为O(nlogn)【数据】样例解释——61 2 2 1 1 2最大值为1时:最大值个数为1、2的区间个数分别为:3 1最大值为2时:最大值个数为1、2、3的区间个数分别为:(1+1+3+1+1+1)(3+3+1)(2)=(8)(7)(2)总区间个数为21答案为(11)(8)(2)(0)(0)(0)=10 + 10 + 1 + 4 + 5 + 6=36*/
0 0
- 【HDU5751 BestCoder Round 84E】【FFT + 线段树求最值】Eades 最大数出现次数为[1~n]的区间个数
- HDU 5751 BestCoder Round #84 Eades(线段树+FFT)
- hdu 5751 Eades FFT(BC Round 84 E)
- 【BestCoder Round 65E】【网络流+讨论 奇偶分类思想】n个数形成若干至少3元素素数环的可行性检验 数可以为1
- hdu5751 Eades
- N个数中,1出现的次数
- 【Codeforces Round 334 (Div 2)E】【博弈-SG函数】Lieges of Legendre n个数 每次取数-1或者变2x为k个x的博弈
- 已知一个整数n,写一个函数f(n),返回0~n间,每个数中出现的“1”的个数,问最大的F(n)= n中n为多少
- 【HDU5750 BestCoder Round 84D】【数学 贪心 复杂度计算】Dertouzos 范围有多少数的最大真约数为d
- poj 3368 统计区间出现次数最多数个数 RMQ
- 【HDU5649 BestCoder Round 76 (div1)D】【二分+线段树】DZY Loves Sorting 全排列1~n 区间升序降序排序 最后k位置的数是几
- n个数里出现次数大于等于n/2的数
- n个数里出现次数大于等于n/2的数
- 好未来:n个数里出现次数大于等于n/2的数
- 1-n个数中1出现的次数
- 函数式线段树(区间数出现次数)
- 数组中n个数出现次数超过1/(1+n),求这些数
- codeforces The Bakery(n个数划分k区间,权值为区间不同数,问总权值最大)
- Thread
- poj2826
- 梦都有醒的时候
- UVa - 815 Flooded! 洪水 二分猜答案+排序 重庆一中高2018级竞赛班第三次测试 2016.7.24 Problem 1
- PAT 乙级1007. 素数对猜想 (JAVA版)
- 【HDU5751 BestCoder Round 84E】【FFT + 线段树求最值】Eades 最大数出现次数为[1~n]的区间个数
- 怎么申请299$的企业开发者帐号 申请的时候应该选择哪个?
- 【ThinkPHP】中,对配置项做了个详细的总结~
- 解决SVN上UUID不匹配问题
- 啪啪啪 打脸啊 数据埋点思路步奏
- Git入门(9)-远程仓库
- MyBatis小笔记
- 精益管理之现场管理改善
- 必须掌握的Java排序算法