codeforces 414C 分治思想运用
来源:互联网 发布:c语言大小写字母转换 编辑:程序博客网 时间:2024/06/05 10:29
这个题很劲啊。搞了我一下午。。
大意是:给你一个2n 长度的随意的数组,有m 次查询,每次从左到右把数组依次分成长度为qi 的块,将其reverse ,问每次翻转之后逆序对数多少
比较难想的一道题。有些逆序对的结论很显然,设一段区间seg 的逆序对数为a 那么翻转这个区间之后的逆序对数为C2|seg|−a 当然不能有重复的数出现,如果有重复的数出现,还需要减去∑C2vi 其中vi 表示i 在区间出现的次数好的有了这些结论。其实并没有什么卵用。。。递归的思路是显然的,我们仿照归并排序的思路,先把左右区间搞出来,然后在计算出左区间对右区间的贡献值。可以在n∗2n 复杂度预处理出来。然后重点就是查询了。一开始我更新到每个节点,设置了懒惰元素。但是不是tle 就是wa 。
之所以说这个题很劲,就是需要很抽象的想法才能搞掉。我们想想对于每一层i ,设最开始在0层,那么这层有2i 个小区间。每个小区间都对答案有一个独立的贡献v ,v 表示这个小区间左半部分对其右半部分的贡献,我们把这一层的小区间贡献的和求出来为dp1[i] ,每当我们翻转这一层的时候,每个小区间都翻转了,但是每个小区间都是独立的,翻转就是一起翻转,于是再直接(归并倒着排)处理处翻转的和dp2[i] 每次翻转就是交换dp1,dp2 。再想想,翻转第i 层,只会影响更大的层数,而不会影响之前的层数(这是因为翻转每个小区间,但是每个小区间的相对位置没变,而较小的层是左区间对右区间的贡献,左右相对位置没变)。
然后每次查询暴力更新最多n 层,在求和输出即可
//// Created by Running Photon// Copyright (c) 2015 Running Photon. All rights reserved.//#include <algorithm>#include <cctype>#include <cmath>#include <cstdio>#include <cstdlib>#include <cstring>#include <iomanip>#include <iostream>#include <map>#include <queue>#include <string>#include <sstream>#include <set>#include <vector>#include <stack>#define ALL(x) x.begin(), x.end()#define INS(x) inserter(x, x,begin())#define ll long long#define CLR(x) memset(x, 0, sizeof x)using namespace std;const int inf = 2e9;const int MOD = 1e9 + 7;const int maxn = (1 << 20) + 10;const int maxv = 1e3 + 10;const double eps = 1e-9;ll dp1[21], dp2[21];int a[maxn], ta[maxn], tb[maxn];int n, m, tot;void build(int head, int tail, int deep) { if(deep == n) { dp1[deep] = dp2[deep] = 0; return; } int mid = head + tail >> 1; build(head, mid, deep+1); build(mid, tail, deep+1); int tota = 0, totb = 0; for(int i = head; i < mid; i++) { ta[tota++] = a[i]; } for(int i = mid; i < tail; i++) { tb[totb++] = a[i]; } ta[tota] = tb[totb] = inf; int la = 0, lb = 0; ll ret = 0, retv = 0; for(int i = head; i < tail; i++) { if(tb[lb] <= ta[la]) lb++; else { retv += totb - lb; la++; } } la = lb = 0; for(int i = head; i < tail; i++) { if(ta[la] <= tb[lb]) a[i] = ta[la++]; else { a[i] = tb[lb++]; ret += tota - la; } } dp1[deep] += ret; dp2[deep] += retv;}int main() {#ifdef LOCAL freopen("C:\\Users\\Administrator\\Desktop\\in.txt", "r", stdin); freopen("C:\\Users\\Administrator\\Desktop\\out.txt","w",stdout);#endif// ios_base::sync_with_stdio(0); scanf("%d", &n); tot = 1 << n; std::vector<int> xs; for(int i = 0; i < tot; i++) { scanf("%d", a + i); } build(0, tot, 0); scanf("%d", &m); while(m--) { int q; scanf("%d", &q); ll sum = 0; q = n - q; for(int i = q; i <= n; i++) swap(dp1[i], dp2[i]); for(int i = 0; i <= n; i++) sum += dp1[i]; printf("%lld\n", sum); } return 0;}
0 0
- codeforces 414C 分治思想运用
- 基本的分治思想算法运用
- codeforces 448C 分治
- A^B mod C的分治思想
- 分治思想
- 分治思想
- CodeForces 448C - Painting Fence(分治)
- Codeforces 448C Painiting Fance 分治
- codeforces 448C Painting Fence(分治)
- java面对大数据 并发时候的分治思想及继承的高级运用
- codeforces 152C 字符串的运用
- 二分搜索(BinarySearch)的分治思想C语言实现
- codeforces 448C C. Painting Fence(分治+dp)
- codeforces 448C C. Painting Fence(分治+dp)
- codeforces 448C C. Painting Fence(分治+dp)
- codeforces 848C C. Goodbye Souvenir cdq分治
- 分治算法的运用
- C语言软件开发思想一(break的运用)
- Orthogonal Matching Pursuit(OMP)正交匹配追踪算法学习笔记
- 华为OJ 初级:DNA序列
- curl进行传值(post)
- 5-2 最长连续递增子序列
- 字符串匹配 之 RK(Rabin-Karp)
- codeforces 414C 分治思想运用
- Git小白教程3---远程仓库克隆到本地
- Android中直播视频技术探究之---采集摄像头Camera视频源数据进行推流(采用金山云SDK)
- 从vb的角度看几种简单的排序法
- java之字节流转换为字符流并讲解打印流
- ionic $ionicScrollDelegate.anchorScroll在安卓上不起作用的解决办法
- Android之SDcard存储
- Spring:源码解读(提纲)
- GZIP压缩原理分析(01)——第一章 序言