-
Notifications
You must be signed in to change notification settings - Fork 0
/
content.json
1 lines (1 loc) · 8.66 KB
/
content.json
1
{"meta":{"title":"Lounode's Blog","subtitle":"OIer/蒟蒻/车万众","description":"好想做个女孩子XD","author":"Lounode","url":"http://blog.lounode.com","root":"/"},"pages":[],"posts":[{"title":"CSP2019 游记","slug":"csp-2019","date":"2019-11-11T13:34:27.000Z","updated":"2019-11-11T13:35:31.998Z","comments":true,"path":"2019/11/11/csp-2019/","link":"","permalink":"http://blog.lounode.com/2019/11/11/csp-2019/","excerpt":"","text":"待更新...","categories":[],"tags":[{"name":"CSP","slug":"CSP","permalink":"http://blog.lounode.com/tags/CSP/"},{"name":"游记","slug":"游记","permalink":"http://blog.lounode.com/tags/游记/"},{"name":"2019","slug":"2019","permalink":"http://blog.lounode.com/tags/2019/"}]},{"title":"「图片分享」 四糸乃","slug":"yoshino-awsl","date":"2019-11-11T13:13:31.000Z","updated":"2019-11-11T13:23:52.233Z","comments":true,"path":"2019/11/11/yoshino-awsl/","link":"","permalink":"http://blog.lounode.com/2019/11/11/yoshino-awsl/","excerpt":"","text":"四糸乃的图片分享喵~","categories":[],"tags":[{"name":"四糸乃","slug":"四糸乃","permalink":"http://blog.lounode.com/tags/四糸乃/"},{"name":"图片","slug":"图片","permalink":"http://blog.lounode.com/tags/图片/"}]},{"title":"「数据结构」 线段树","slug":"segmenttree","date":"2019-11-10T14:56:16.000Z","updated":"2019-11-11T13:23:20.659Z","comments":true,"path":"2019/11/10/segmenttree/","link":"","permalink":"http://blog.lounode.com/2019/11/10/segmenttree/","excerpt":"","text":"假设有这么一些问题: 这些问题都可以抽象成若干个区间操作,那么问题来了,如何处理这些操作呢? 首先我们考虑一下朴素做法,在每次操作时,用 \\text{for} 循环每次从操作区间的左端点循环到右端点,在这个过程中维护一些信息,查询同理。 但很快我们就发现,这种方法实在是过于低效了,假如每次操作都是从区间的开头循环到结尾,那么这样的时间复杂度就是 O(n^2) 的,对于一些查询次数在 10^5 以内的操作就会 \\text{TLE} 。 那么如何去优化算法,使它能处理一些区间的问题呢? 先来想想为何朴素做法的时间复杂度不能被接受,因为它对于每个操作,都进行了一遍更新。考虑之前接触过的记忆化搜索、递推等,我们想到:是否能在一次操作中用一些方式 存下 这些信息,然后用到的时候再朴素的求呢? 答案是可行的,想想我们之前学过的前缀和与差分,其核心思想就是这样。 比如现在让你求这个序列 S 某一段区间 \\text{[l,r]} 的和。 我们可以考虑对这个序列做一个前缀和操作,使其变成下图这样。 然后这段区间的和就变为了 S_{r+1}-S_i 。我们就在 O(n) 的预处理 O(1) 的查询复杂度内得到了答案。 但是这样做的话是不支持修改的,如果需要修改的话每次都要重新对序列求一个前缀和,它又退化到了 O(n^2) 查询次数一多还是会 \\text{TLE} 。 那么还能如何优化呢? 不如分析下这些问题,我们发现,这些问题都是对区间的一系列操作。废话?不不不,这正是接下来的重点,既然都是维护区间的操作的话,我们能不能在记录信息的时候记录的是 区间 的信息呢? 显然是可以的,那么如何实现呢? 对了,结构体!我们可以用一个结构体来保存一个区间的信息。 12345struct Area { int l; //区间左端点 (Left) int r; //区间右端点 (Right) int dat;//区间的信息 (Data)}; 有了这个后,我们接着来想下一步怎么做。如何简化修改与查询呢?对,分治,可以吧这个大区间分成若干个小区间,对于大区间的操作直接进行,对于小区间的操作再逐个完成。 在这里,我们正式引入 线段树 这种数据结构。 何为线段树?线段树即为一种维护区间满足 结合律 的信息的数据结构。 结合律:在一个包含有二个以上的可结合运算符的式子中,只要运算符的位置没有改变,运算的顺序就不会对运算出来的结果有影响。重新排列式子中的括号不会改变表达式的值。 比如: a+b+c=a+(b+c) , a \\times b \\times c=a \\times (b \\times c) 考虑将一个区间 \\text{[1,n]} 分割成最多 2^{\\left\\lceil \\log{n} \\right\\rceil + 1} 个子区间(如下图),我们发现这些子区间正好组成了一棵完全二叉树,那么我们就可以用堆式存储。 p 为当前节点编号, 2p ,为当前节点左儿子, 2p+1 为当前节点右儿子。 那么就可以用 p \\times 2 、 p \\times 2+1 的方式来访问每个节点的左儿子与右儿子。 那么,对区间 [3,7] 的操作就可以转化为:对子区间 [3,4],[5,6],[7,7] 的操作。 由于树高最多为 \\log{n} 层,那么每次操作的时间复杂度就是 O(\\log{n}) 的。 那么我们应该如何建立这棵线段树呢?递归! 但在这之前,先要注意一点:我们把 \\text{[1,n]} 的这个区间分成了最多 2^{\\left\\lceil \\log{n} \\right\\rceil + 1} 个子区间,这样的话线段树需要的空间就大约变为了原来的四倍,一定要注意在原来的数据范围上开 四倍空间 ! OI-wiki: 分析:容易知道线段树的深度是 \\left\\lceil \\log{n} \\right\\rceil 的,则在堆式储存情况下叶子节点(包括无用的叶子节点)数量为 2^{\\left\\lceil \\log{n} \\right\\rceil} 个,又由于其为一棵完全二叉树,则其总节点个数为 2^{\\left\\lceil \\log{n} \\right\\rceil +1}-1 。当然如果你懒得计算的话可以直接把数组长度设为 4n ,因为 \\frac{2^{\\left\\lceil\\log{n}\\right\\rceil+1}-1}{n} 的最大值在 n=2^{x}+1(x\\in N_{+}) 时取到,此时节点数为 2^{\\left\\lceil\\log{n}\\right\\rceil+1}-1=2^{x+2}-1=4n-5 。 1234567891011121314151617struct SegmentTree { int l; int r; int dat;}t[10010 * 4]; //四倍空间一定要注意,否则会REvoid build (int p, int l, int r) { //当前节点、左端点、右端点 t[p].l = l; //子区间的左端点 t[p].r = r; //子区间的右端点 if (l == r) { //l=r时,到达叶子节点 返回 //do some thing return; } int mid = (l + r) / 2; //将当前区间分成两半 build (p * 2, l, mid); //递归左子树 build (p * 2 + 1, mid + 1, r); //递归右子树 //do some thing}","categories":[],"tags":[{"name":"数据结构","slug":"数据结构","permalink":"http://blog.lounode.com/tags/数据结构/"},{"name":"线段树","slug":"线段树","permalink":"http://blog.lounode.com/tags/线段树/"}]},{"title":"「题解」 Luogu P5613 [MtOI2019]黑蚊子多","slug":"luogup5613","date":"2019-11-10T11:52:25.000Z","updated":"2019-11-11T13:12:23.621Z","comments":true,"path":"2019/11/10/luogup5613/","link":"","permalink":"http://blog.lounode.com/2019/11/10/luogup5613/","excerpt":"","text":"真人面对面收割,美女角色在线掉分,发狂玩蛇新天地。 ---Arcaea中文维基 以下是正文 可以考虑这么一张图: 每次向上走 m 格,在其中有 k 个特殊平台,踩上去后后面每次向上走 m+1 格。 对于 60% 的数据,k = 0。 那么要从底部到达顶部所需要的最小次数就是 \\frac{n}{m} 次,只需要输出 \\frac{n}{m} 即可得到此部分的分数。 对于 100% 的数据,1 ≤ m ≤ n ≤ 1000 ,k ≤ 10 。 1≤ n ≤ 1000 所以我们可以开一个数组存储哪些是特殊平台 ,然后模拟就好了。 12345678910111213141516171819202122232425262728#include <bits/stdc++.h>using namespace std;int main () { int n,m,k; int a[1010]; cin >> n >> m >> k; for(int i = 1; i <= k; i++) { int in; cin>>in; a[in]=1;//存储特殊格子 } int ans=0; int t=0;//当前位置 while (true) { if(n-m<=0) {//边界 ans++;//即使剩余格子小于m 也还是需要走一次的 break; } n-=m;//剩余格子 t+=m;//当前位置 m+=a[t];//如果特殊为格子 m+=1 ans++; } cout<<ans; return 0;}","categories":[],"tags":[{"name":"题解","slug":"题解","permalink":"http://blog.lounode.com/tags/题解/"},{"name":"模拟","slug":"模拟","permalink":"http://blog.lounode.com/tags/模拟/"}]},{"title":"Hello World","slug":"hello-world","date":"2019-10-03T16:00:00.000Z","updated":"2019-11-11T13:36:02.474Z","comments":true,"path":"2019/10/04/hello-world/","link":"","permalink":"http://blog.lounode.com/2019/10/04/hello-world/","excerpt":"","text":"第一篇博客吧.QwQ 测试Markdown语法. 顺便放点更新日志: 19.10.4 Blog初步搭建完成,添加了看板娘。 19.10.5 添加了评论系统。 19.11.10 换了主题、Markdown渲染插件。","categories":[],"tags":[{"name":"杂项","slug":"杂项","permalink":"http://blog.lounode.com/tags/杂项/"}]}]}