一句话题解(20170801~20170125)
8.1
bzoj 4720 noip2016 换教室 floyd预处理+期望(薛定谔的猫)
bzoj 4318 OSU! 三次函数期望值 从一次、二次推得
8.2
bzoj 1076 状压+期望DP 逆拓扑序(贪心常用手段防止现在过度影响未来)lim边界问题曾WA多次
bzoj 1012 树状数组(线段树)第二 暴力更新后缀第一(明显可卡) 暴力查询要TLE 单调栈没调出来
//bzoj 1010 toys玩具装箱 单调性
//bzoj 1006 弦图染色裸题 诱导子图、完全图、团、最小染色、最大独立集、最小团覆盖、弦图、单纯点、完美消除序列(字典序广度优先搜索LexBFS、最大势算法MCS)
//bzoj 4605 二维 单点修改 询问矩阵第k大
8.3
bzoj 1011 误差分析 5% 几乎是暴力
bzoj 2348 序列单调性
bzoj 1007 离线维护下凸壳 开double(eps) 单调栈 直线交点公式!! 特判k相同 2种比较方法 可只开1个struct数组 一个int数组
8.4
bzoj 2724 求区间众数(无修改) 分块 离散化(离散过去切莫忘记离散回来!!!) 求块间众数(及出现次数) 求前缀和(每个数出现次数) 简单累加运算 O(n sqrt(n))为什么跑的那么慢!!! 强制在线 取最小
bzoj 2748 背包DP 居然是省选题!!!
8.7
bzoj 4721 NOIP2016worm 3个队列 先排序 单次O(1) 选出后宰断放入后2个队列 前缀和 注意选取时的边界条件(比大小) RE了说跪就跪
bzoj 2818 yy的gcd简化版 积性函数
bzoj 4472 树形DP if内pair的first与second判断
bzoj 2563 贪心 注意统计的方式 应用很广
8.8
bzoj 3195 十分经典 做的极优 状压非打表 滚动数组 枚举顺序(类似完全背包) 空间2*M*2^k 时间n*(m*2^k+m*k*2^(k+1)) 大量减少枚举 且1A
8.9
bzoj 1003 SPFA预处理 DP区间覆盖问题 是一道当之无愧的好题 注意边是M<<1 n是天数,m是点数要区分开
bzoj 1257 理解取整 根号类计数
bzoj 1207 DP 看似M^2 前缀和优化 大大提速 快了1980 ms/64 ms=30.9375
bzoj 1303 (前缀和 “滚动”数组颇像DP)这是我当时的做题记录。但其实当时理解的确实不透彻。为什么题目要求的是奇数?偶数为什么不可以?绝不仅仅是中位数不好确认这么简单。题目要求中位数是b,那么>b的当+1,而
???BZOJ 1022 为什么是对的 ANTI—SG
bzoj 2257 先看了题解 贝祖定理 找最大公约数 暴力展开
8.10
bzoj 1029 priority_queue是大根堆 贪心+堆
bzoj 4952 二分答案裸题 但lf与rg要开得很大 WA到怀疑人
bzoj 3680 “模拟退火”乱搞 找平衡点 还可以三分 多次逼近
!!!!!!!!!!!!bzoj 3670 死活调不出来 到底怎么做啊???
8.11
bzoj 1680 贪心 仔细分析样例很容易想到 最开始以为是DP或网络流
bzoj 1083 MST模板题
bzoj 3670 KMP的升级
bzoj 1293 2-pointer 类似莫队 或者 保存每个颜色的位置相当于暴力枚举
bzoj 1046 LIS 树状数组优化DP 或 单调栈+二分优化DP 直接统计 开始题读错了以为是值的字典序最小结果却是下标的字典序最小可以直接扫一遍
8.12
bzoj 1019 可以打表找出规律(康托展开)本质上是直接的转移关系 也可以DP(该DP方法很经典) 但注意要开long long n原题为30但实际上可以开到高精度
8.14
poj 1141 括号匹配 区间DP 递归输出方案 注意空行的影响(决不能用scanf只有请gets或getline了) 确保pos不为0很好。
8.15
bzoj 4709 柠檬 单调栈+DP 详细分析过程 不知为何二分。20180113更新,终于会了斜率优化DP,是我太傻了还是之前的讲课人太傻了……不过说,我似乎在懵懂中也当过一回讲课人……XGG那回上课一点,下来一想就通了,看来契机是很重要的,不过看来还是有很多人看似会了其实不会……这道题目要使截距最大,应当维护上凸壳。而加入点的x和y都是有序的,于是可以使用单调结构维护。而询问的k是单增的,于是使用单调栈即可。凸包不能妄删,但是这样的删头删尾确实完全可以接受的。原因很简单,删掉了这个点是因为它不合法,而删掉这个点后可能新出现在凸包中的一定也是不合法的。而网上很多人写二分,其实也有它的原理。就是NEITHER_NOR划式子划不下去了,又知道是斜率优化,于是比较不用斜率而是二分什么时候超过对方。这样……其实也不是不可以,只是真的很挫。
bzoj 4008 迷之TLE(后来发现是根本没有记忆化) 但顺推以后很快 调得很快乐
9.23
UOJ 35 后缀数组模板 当时SAM过了SA却有错 当时百思不得其解直至绝望 最后发现是刘汝佳的后缀数组有错 所以说尽信书不如无书 注意枚举的顺序!
9.25
BZOJ 2064 状压DP 可以是二维的 也可以是一维的 本质相同 最优子结构的充分应用 详见SIP
BZOJ 1665 暴力建图 最短路水题
BZOJ 3727 昨晚的考试题,n大了很多倍,无由a推b,无多组数据,最开始并没有发现。于是先RE,再TLE,从BZOJ上粘下来改一下直接交又CE了(可恶的
Main.cc:63: error: stray ‘\357’ in program
Main.cc:63: error: stray ‘\273’ in program
Main.cc:63: error: stray ‘\277’ in program
)然后再交又PE了……最后把行末空格处理了一下才AC……
感到很崩溃,一道题数据(BZOJ 2709)有鬼~~~您已达到日上限50次……
最后也查出来了,只是因为最后的空格,让人抓狂到崩溃。实质上跟下面的BZOJ1070是一样的。
NOIP TRADE 当时写的很难看,于是重新写了一遍。当时还用了2次SPFA,事实上为什么要写2个呢?
9.26
BZOJ 4569 并查集+分块或ST表 分块需用fread
BZOJ 3991 性质题 DFS序 ST表 SET维护很方便
BZOJ 1026 经典的数位DP又做了一遍 发现自己还是有很多问题啊……
BZOJ 1070 正在苦苦调试中……最后的最后,调试出来了,发现自己真是……最开始的错因:1.小数保留位数2.不合法库3.dis4.空间。然而,这一切应当都很好调,只是在最后以为已经改完的时候,作死的改了一处,导致了致命的错误。之后便逐渐陷入疯狂,刷得水反而效果很不好。然后就可以反思了,最开始问题并不多,常在细微处,但是都可以产生致命影响。不容易发现,就能让一个人陷入癫狂。这还不是考场上,而这类问题的解决只能是一次正确,没有更好的方法。一道题目应当反复咀嚼,一些典型的小错误需要时时警惕。逻辑不能乱,头脑要时刻清晰才行。
9.29
BZOJ 1296 偶然看到,犹忆寒假时做过,于是点进去看了一下,整个人都不好了……风格奇怪不说,而且能够O(n)开出来的空间结果用了O(n^2)的……于是立即修改,空间复杂度大减,但时间复杂度基本上没变。观察后发现可以使用单调性直接解决一维,最大的四维变成了三维,但时间复杂度还是没变。整个人很纳闷,于是看了看STATUS,结果基本上都是200ms以内,而我300ms+。于是分析了hzwer学长的代码,ta的枚举是四维的但是却在150ms以内,最后终于发现,是自己to young to simple啊。进行修改,最后40ms进入rank前10。
为什么呢?列表如下,十分明显(N,M≤50,T≤2500):
我寒假时的代码 | 降维以后 | 修改边界以后 | hzwer | |
空间复杂度 | O(NM+(N+M)T) | O(T) | O(T) | O(M^2+NT) |
所占空间 | 3000 kb | 840 kb | 840 kb | 1800 kb |
时间复杂度 | O(NM+NT(M^2)+N(T^2)) | O(N(M+MT+T^2)) | O(N(M+M^2+MT)) | O(N(M+M^3+MT)) |
运行时间 | 340ms | 340ms | 40ms | 150ms |
9.30
NOIP LANDLORD 斗地主 在luogu上AC,但在BZOJ上0msWA……
NOIP ANGRYBIRD 不知为何,在luogu上只有85……
10.1
BZOJ 3751 NOIP 解方程 f(n)=0→f(n)≡0(mod p) f(n)≡0(mod p)~>f(n)=0 又因为f(n)≡f(n+k*p)(mod p),故可用hash得到答案(超级近似解)毕竟HASH KILLER3无人AC啊……
BZOJ 4719 NOIP 天天爱跑步 沿LCA拆分路径,然后考虑一条路径对答案的贡献,可以发现简单的线性关系。这样的关系其实是询问子树,而又可以使用差分+桶来简单维护。注意实际统计的是差量。
10.2
BZOJ 1193 有公式,但是可以大范围贪心,小范围爆搜啊
TO BE DONE:BZOJ 1822 GRAPH WA NOW
TO BE DONE:BZOJ 3876 GRAPH
TO BE DONE:BZOJ 3065 DS
TO BE DONE:BZOJ 1922 GRAPH IN PROGRESS
TO BE DONE:BZOJ 故乡的梦 GRAPH
TO BE DONE:BZOJ ali's printer STRING
TO BE DONE:BZOJ 海拔 GRAPH
TO BE DONE:BZOJ 财政官
TO BE DONE:BZOJ 亚瑟王
TO BE DONE:BZOJ 2095
′BZOJ1375-双调路径(双权值的最短路) ′POJ1860-货币兑换(Spfa判断正环) ′BZOJ1097-旅游景点atr(dijkstra堆优化+状压DP) ′BZOJ2763-飞行路径(分层图跑Spfa) ′BZOJ1576-安全路径travel(dijkstra预处理最短路径树+并查集)
′*POJ1275—(不等式含有未知数,通过二分确定最大解) TO BE DONE IN A YEAR:BZOJ 4062
需注意:不要依赖别人的代码。不要一次UNACCEPTED以后就去抄。
10.3
BZOJ 1922 POI1999灌水法 今天T2的复制
BZOJ 2733 DS 永无乡 启发式合并 因为没有拆分,所以如果小并大会很优,因为可以证明很优,而且该策略对人们有很大的启发,所以叫“启发式” 使用并查集按秩合并,然后线段树跟着合并。线段树合并时可以使用类似于左偏树的优秀合并方法,最后均摊单次合并复杂度O(1),总的复杂度为O(nlgn)。是很优秀的。但是,需要注意,最好不要压行,这样修改会方便很多。
10.4
BZOJ 3688 贪心 NOI2014D1T1 二进制拆分 从高位到低位 尽可能得分 同等状况尽可能选0
10.5
BZOJ 2741 可持久化Trie+分块 思想很简单,但很有效 最开始是7月份一道测试题,当时因为自己搞不清楚集合的边界,所以WA了。 后来直接交RE,因为L+ans会超long long。 但是当时再交就TLE了,一直拖到现在才解决。原因主要是分块的大小问题,当时东西没有学到家,块居然开成了sqrt(n/lgn),还以为比sqrt(n)优,实在是naive啊。另外,可以进一步地用空间换时间,这就涉及到空间的精打细算了。
BZOJ 2724 蒲公英当时已经做过,当时是没有考虑到离散化,没有把belong的大小开对,不过都是小问题。大问题是当时深深的疑惑:为什么我是O(nsqrt(n))的却比O(nsqrt(n)lgn)慢?现在一看,才发现实在是naive。我在每一次询问都暴力的memset,那么就应该是nq/4的复杂度,能过过确实让我颇为惊讶。但是改成了清零先有WA了,仔细分析后找到了好的方法。现在说说,为什么我快?因为我空间开的大,我存了任意两个块之间的众数及出现次数,及每个数到每个块的末尾的出现次数(前缀和)。空间和空间都是O(nsqrt(n))的。而像hzwer的做法是给每个数都开一个vector,查询时log二分卡出。这样空间就是O(n)的,而时间却是O(nsqrt(n)logn)。请注意上面的“卡出”,这就是我和hzwer的不同之处。我的做法是用O(nsqrt(n))的空间和时间预处理出每个数的前缀和,查询是O(1)的。而hzwer是用vector,是O(n)的空间和时间预处理,查询就是O(lgn)的了。这就是这么个道理,有得必有失,所以许多事情都要用辩证的眼光去看它,在特定的时间做出正确的选择。在扯浑点儿,就是贪心了。
10.6
BZOJ 3252 攻略 裸的长链剖分,直接递推就是了。个人认为,偶尔追求速度是可以的,但是绝对不应当以牺牲大量时间为代价,不应过于钟情那些奇技淫巧。fread这个东西还是要慎用啊!
10.9
BZOJ 1529 每个结点都只有一条入边,所以是有向的基环外向树。只要在基环上选一个点,就可以搞定整个联通块。所以不是tarjan因为卡空间,而是并查集联通块计数。
10.10
BZOJ 5042 一道十分恶心的卡常题。是一道裸的RMQ,虽然求解RMQ有很多方法,但是此题的n≤3000000还有q≤1500000就十分恶心。看上去只能用O(n)的离线RMQ过,其实并不难写。但是,我看见网上有人用ST表A了,而且只开了11层,只能说我们simpsonk的数据有鬼……
10.12
BZOJ 4950 虽说是今年的WF,但确实很巧妙。相当于是在平地上堆了一些方块,问最少用几块方块可以再堆出一个使得三视图与之前相同。贪心的思考,发现俯视图上该有的点一下就是了,之后每一行每一列挑一个出来最高就是了(数据肯定合法的)。然后就可以二分图匹配,因为行列统一最高的就可以少堆几个箱子。
BZOJ 4562 就是一道很水的拓扑排序,但是要注意单独的一种孤立生物不算一条食物链(当时没看完题),要特判之前还不知道。食物链是一条完整的链,边怎么建都是对的。
10.13
BZOJ 2730 割点分隔出来的叫点双联通分量,边分隔出来的叫边双联通分量。每个点双联通分量若无割点则需建2个,若有一个割点则需建一个(当然不建在割点上),若有多个割点就能直接藐视掉。
10.16
BZOJ 4326 彻底搞明白了XGG的方法,被征服了……
BZOJ 3594 方伯伯的玉米田 枚举的顺序很重要,大家写的都是二维树状数组。可我为什么就是觉得可以更快呢?
BZOJ 4726 SABOTA一道非常好的树形DP,虽然代码非常短。边界要注意,详见SIP。
BZOJ 2131 免费的馅饼 二维偏序 先排序再用树状数组,pandragon改成了saber
10.17
BZOJ 1977 一道很好的很经典的题目,严格次小生成树。因为是严格次小生成树,所以肯定是一条非树边替代了树上路径的一条边。这条非树边的权值一定大于等于树上路径的最大边权,如果大于就直接用最大边权替换,如果不行就用严格次小边权替换。先把最小生成树建出来,再把边建出来倍增,询问时同时找出最大边权和严格次小边权进行更新。当时没有保证是严格次小边权,就WA了。
BZOJ 3732 给你一个图和若干次询问,每次询问需要查询从u点到v点上所有路径上的最大边权的最小值。很显然,MST有着非凡的性质。只走树边一定是最优的。其余就和1977很类似了。
10.18
BZOJ 4808 给你一个方格图,部分地方不能放马。你放的马不能互相攻击(不考虑蹩脚),问最多能放多少个马。乍一眼很难下手,但其实能攻击的马一定是黑白不同色的(国际象棋),于是可以二分图解决。因为最小点覆盖=最大匹配,最小边覆盖=最大独立集=n-最大匹配。但具体是为什么啊???
BZOJ 1475 方格取数。意识到是二分图以后就可以直接最小割解决了。
BZOJ 4443 小凸玩矩阵。方格图中选择n个数(不同行不同列),使得从小到大排序第n-k+1个数最小。考虑最开始随机选择n个数,在值域上是较均匀分布的。而我们要做的事情是要让第n-k+1个数最小,即是压缩前n-k+1个数形成的区间。只要想一想,在压缩前右边的区间就能选出k个数,在压缩后自然更不成问题。于是问题具有单调性,可以使用二分答案。怎么check呢?已经说过,右边选k个数很简单,左边选出n-k+1确是技术活儿。但是仔细想一想也不难,只要选出n-k+1个不同行不同列的优秀小数就够了。图实在过密,总复杂度O(n3lgn),导致原来清零used的O(nm)比用大一统TIM和int used要快整整20ms。
BZOJ 3884 上帝与集合,一道优秀的数学题(POPOQQQ的题)。一次除以二一定要除净,不然会很不优。分奇偶,用根号级别的复杂度算phi会优秀很多。以为记忆化可以加速,发现自己失败了……map无用,求phi时使用sqrt不一定更优(使用sqrt耗时84ms,使用i*i<=x耗时44ms)。快速幂带入运算的幂数必须是正数。因为右移一个int是把它的第32位到第2位右移到第31位到第1位,所以-1右移还是-1。
BZOJ 4326 XGG真是强!卡常卡出新境界……
BZOJ 2427 软件安装。可以使用tarjan,但是毕竟图是基环外向树所以可以直接搞。最好还是用栈存起来,每一次其实是染色的过程。把环缩成点然后求解,就是一个树形DP。可是,最开始我居然还WA了。原因让人很痛苦,因为是必取状态,所以1~cost[u]-1的状态是完全非法的,hzwer一干人等是先把子树处理完,再暴力加上子树根,但个人认为最好的方法还是把完全不访问1~cost[u]-1的状态,应该这样是完全正确的。
BZOJ 2124 拓展LUCAS定理,解决n、m较大且p是一般数但p比较小的问题。做法是算出C(n,m)%pik,然后使用CRT整合。怎么计算那个式子?考虑到C(n,m)中能抽出p的个数很容易计算(对于n!,能抽出一个p的有n/p个数,在此基础上能抽出两个p的(n/p)/p个数……),于是我们只需要算出n!在除去因子p后%pik是多少。因为%pk存在循环节,所以可以方便地加速。先不考虑p的倍数,在各抽掉一个p变成新的阶乘继续处理。关于整合这一关,可以先预处理出来。然后什么时候该模什么数呢?最外层相乘肯定%MOD,内层变成了∑...*...,也模MOD。再进一层到了统计或递归层,就要%pk了。当时有一些细节没有想清楚,就AAWW了很多遍……
1 #include
2
3 int MOD;
4
5 int mpow(int a,int b,int mod) {
6 int res;
7 for( res = 1; b; b>>=1, a=(long long)a*a%mod ) if(b&1) res=(long long)res*a%mod;
8 return res;
9 }
10
11 void exgcd(int a,int b,int &x,int &y) {
12 if(!b) {x=1;y=0;return ;}
13 exgcd(b,a%b,y,x);y-=a/b*x;
14 }
15
16 int inv(int x,int mod) {//gcd(x,mod)==1
17 int a;
18 exgcd(x,mod,a,x);
19 a=(a%mod+mod)%mod;
20 return a;
21 }
22
23 int muk(int n,int p,int pk) {
24 if(!n) return 1;
25 int ans = 1;
26 for( int i = 2; i <= pk; i++ ) if(i%p) ans=(long long)ans*i%pk;
27 ans=mpow(ans,n/pk,pk);
28 for( int i = 2, j = n%pk; i <= j; i++ ) if(i%p) ans=(long long)ans*i%pk;//注意把i%p==0给过滤掉
29 return (long long)ans*muk(n/p,p,pk)%pk;//注意是n/p
30 }
31
32 int COMB(int n,int m,int p,int pk) {
33 int a = muk(n,p,pk), b = muk(m,p,pk), c = muk(n-m,p,pk), k = 0;
34 for( int i = n; i; i/=p ) k+=i/p;
35 for( int i = m; i; i/=p ) k-=i/p;
36 for( int i = n-m; i; i/=p ) k-=i/p;
37 return (long long)a*inv(b,pk)%pk*inv(c,pk)%pk*mpow(p,k,pk)%pk;
38 }
39
40 int list[7], val[7], vassal[7], tot;
41 void init() {
42 int x = MOD, v;
43 for( int i = 2; i * i <= MOD; i++ ) if(x%i==0) {
44 list[++tot]=i;
45 v=1;while(x%i==0) x/=i, v*=i;
46 val[tot]=v;
47 vassal[tot]=(long long)(MOD/v)*inv(MOD/v,v)%MOD;
48 }
49 if(x!=1) list[++tot]=x, val[tot]=x, vassal[tot]=(long long)(MOD/x)*inv(MOD/x,x)%MOD;//copy下来注意完全修改
50 }
51
52 inline void ADD(int &a,int b) {a=a+b>MOD?a+b-MOD:a+b;}
53 int COMB(int n, int m) {
54 // if(m>n) return 0; 为了严谨肯定加上最好
55 int ans = 0;
56 for( int i = 1; i <= tot; i++ ) ADD(ans,(long long)COMB(n,m,list[i],val[i])*vassal[i]%MOD);
57 return ans;
58 }
59
60 int w[6], sum;
61 int main() {
62 scanf("%d",&MOD);
63 init();
64 int n, m, ans = 1;
65 scanf("%d%d",&n,&m);
66 for( int i = 1; i <= m; i++ ) scanf("%d",&w[i]), sum+=w[i];
67 if(sum>n) {printf("Impossible\n");return 0;}
68 for( int i = 1; i <= m; i++ ) ans=(long long)ans*COMB(n,w[i])%MOD, n-=w[i];
69 printf("%d\n",ans);
70 return 0;
71 }
BZOJ 2124
BZOJ 1601 当时ACM的一道题。可以建一个虚点水过去,也可以使用这道题目的特性。即是假设最开始所有点都与虚点相连,然后不断加边的时候三角形删掉短边。
10.19
BZOJ 1042 硬币购物。一开始给定4种硬币,随后是1000组询问。每组询问是每种硬币有使用上限,此时能够刚好凑出s块钱(s≤100000)的方案数。我觉得这种题,T*2n的复杂度还可以把数据范围大大扩张,不过方法确实只有那么一种。如果不加数量限制就是普通的完全背包,但是因为有限制所以我们需要减去一些东西。减去什么?无法完全覆盖就只有多减,减得太多又要加回去……就是一个容斥的过程了。而怎么减?举个例子,1号硬币超标的方案数是f[n-c[1]*(d[1]+1)],这之中显然利用到了完全背包的性质。就像BZOJ2287消失之物的n方做法充分利用到了01背包的性质一样。
10.22
BZOJ 1833 数字计数。当我觉得可以1A时,0msWA。后来查错,发现有东西少加了,便立马补上,交了却又是0msWA。不理解,再去查,发现用了%I64d,便立马改正,交上去WA了第三发。整个人陷入崩溃,手造数据和hzwer比对不出来,感到十分疑惑,便交了hzwer的,1152kb880ms。于是整个人更加蒙了,就又交了一下第三发的,还是WA。最后终于想到对拍,结果第一组随机数据就发现不一样(天公佑我!)。仔细查错,发现一个该用longlong的数组我当时无脑int,导致了第三发的WA。于是交了上去,0msAC。空间打算再卡一卡,但看来是真不行了。
BZOJ 2873 光之大陆 一道计数DP,非常优秀。把思路彻底打开了,重点在定义状态,状态定义是f[i][j],j表示基团数。这里的基团套用了化学中的概念。
10.24
BZOJ 4325 斗地主。当时提交不断的WA,把数右推就解决了,整个人十分迷乱。后来找lydsy要到了数据,终于发现隐形越界的致命伤害。看来一定要把数组开大那么一点点(至少大10),因为隐形越界真的很不容易发现。
10.25
BZOJ 1028 麻将。一共有n(n≤400)种牌的编号,3*m+2(m组3张牌顺子或刻子+一对牌)张牌和牌。现给你3*m+1(m≤1000)张牌,问听那些牌(如果有那一张牌就可以和牌)?明显发现,只有枚举一遍听牌O(n),只有枚举一遍一对牌O(n),之后怎么判断一副牌可以三三分成一组呢?看到n,我们可以确信这个check是O(n)的。刻子就是三张一样的牌,顺子就是三张连续的牌。考虑又可以出刻子又可以出顺子的情况,肯定是一次出完刻子更优(自行脑补一下),如果出顺子更优那顺子一定不比刻子少那还不如出刻子。所以就这么扫一遍就好了。边界条件其实不比太在意,因为for i = 1->n中处理的是i,i+1,i+2,那么如果n-1和n非法了,那显然就是非法的。
如此想来,这道题和NOIP05T3过河其实挺像的。两点之间距离虽然长,但却可以直接把多的略去只考虑剩下的一小段。贪心的策略,却很有道理。
10.26
BZOJ 4552 排序。ZYC讲的,给你一个n的排列与q次操作,每次操作是把一段区间按升序或降序排序,询问最后pos号位置(只询问一个位置)是什么数、看似根本无法下手,除非用ZJC的无敌值域线段树套splay。但是,可以发现一种特殊的单调性:定义一个数值standard,把≤standard的位置标记为0,把>standard的位置标记为1,然后原来线段树的值域就变成了2。再操作q次,就能够知道pos号位置的数与standard的大小关系。想到这里,那显然就已经可以二分答案了。二分O(lgn)次,单次check是O(nlgn)的,不愧于n≤100000的数据范围。但是,我自以为无错但交上去就立即RE,调试许久无果。于是自己构造数据,发现n=5时我就能够RE了……这果然又是一个思维的死角。以前做线段树时都保证了区间合法,但是我们在做此题的时候很有可能是不合法的,如果不特判就会直接RE。这显然是极不值的,少一句特判100行变成废品,虽然有的不合法区间会被直接消化掉(线段树的特性),但是有太多并不会。多一句特判,万事足矣。
BZOJ 1598 很快就把第k短路写出来了,不过用的是A*。专业的我不会,就只有照LXY大佬的方法做了。先在反图中跑一遍最短路,再A*优化暴力BFS求出k条路径。网上有人说A*可卡,这应该是挺显然的事情。不过A*为什么是正确的?其实更显然。如果直接暴力BFS就只能算贪心,再加上反图的最短路实质上就有了估价。估了准确的价,就可以先跑更有希望的辣!
专业的第k短路算法绝对不会被卡。做法是:建立出以t为根的最短路径树。考虑一条路径对应的是一个非树边序列,故可以在堆中存储的状态为现有的距离与最后的边。更新时要么后面加一条边,要么换一条边。具体加什么换什么呢?使用可持久化堆就可以啦,加就加堆中的根,换就换现有的儿子。总体复杂度为nlgn级别。
LUOGU上水了几道题:寻找道路(14D2T2,我两遍BFS)、靶形数独、过河、火柴棒等式
还打算做:愤怒的小鸟(为什么我只有85!!!)、华容道、Mayan游戏、飞扬的小鸟、树网的核
10.27
BZOJ 1999 树网的核。NOIP的数据范围是300,但这里妥妥的500000。求直径当然简单,“偏心距”在一条直径上但确实是固定的。当时以为只用管直径的两个端点,发现自己naive了。实际上单单2-pointer不够,我还用了RMQ(往直径外最远距离)!!!线段树敲出来AC了,但效率实在太低。最后发现,其实最后处理就好了。因为在区间外的一定不会影响答案,更新了完全也不会影响。但是460ms的大佬到底是怎么写的!!!
NOIP 愤怒的小鸟。终于明白自己WA在什么地方了,是没有开eps和特判2个x相同的情况。做法其实很简单,我是每一次枚举i和j把所有满足的k都找出来进行更新,并保证这条曲线不再更新。很明显这样就是O(n*2n),而如果多次更新同一条曲线就会TLE。eps真的很重要,比较相等的时候最好统统加上eps。
NOIP 飞扬的小鸟。这题还WA了好几次。最开始只是没有注意到应该“转移时放敞之后加限制”,但是改的时候又乱改还根本看不到。你要是问我怎么看到的?我自己跑一组数据得到的和Cena上测的完全不一样,整个人迷乱了好久才发现空间的ZZ问题。实在是naive!!!其实本无问题,只是改错时顾头不顾尾,乱改反而要花费更大的代价。
NOIP 虫食算。最开始只有60分,然后调整字母填入顺序(从高位到低位),就有了80分。没有办法,就改变了填数的顺序,于是AC。调整枚举顺序的优化最玄学……
10.28
NOIP 华容道。之前一直没有发现错误,但就是连样例都跑不出来。最后才发现挂在了哪里,原因让人很伤心。我有2个BFS,一个中间调用过另一个,却想着节省空间只用了一个queue。很显然这样会jiji,而我当时却迷乱了好久,并且曾认为是queue的锅。Naive啊!方法很简单,就是把空格先挪到s旁边,然后空格会挪到s的另一个旁位,或是空格与s互相移位。做法就是使用一个BFS预处理出一个n^2*4*4的数组,然后对于每组询问像上面那样不过是SPFA。注意有特殊情况需要讨论。
BZOJ 1123 BLO。无向图tarjan求割点的同时统计断开的点的对数。最开始WA了,原因是如果之前的是不断的而后面的是断开的,如果直接使用siz[u]就会少统计很多值。一对拍就立马发现了,这种东西如果在考场上就会很让人伤心,因为明明只差那么一点点,却就是很多很多很多的教训。
10.30
BZOJ 2330 糖果。就是一道普通的差分约束,还挺有名的。
NOIP MAYAN。最开始70,之后加了交换防同色就成了80。之后让每一层有了独有的Mayan类防止多次反复申请,先是少了一层就只有60,加上以后还是80但确实快了一点。然后加了一个剪枝,无奈最后发现有问题。此时突然发现,如果直接按照最小字典序搜索,那么只要找到解就可以输出了。于是重新调整了枚举顺序,但是我的if判断条件边界出现了问题。又经过了调整,终于AC。速度很快,就真的是模拟了。这样的东西确实有必要分模块编程,整个思路也会清晰很多。
10.31
BZOJ 2142 礼物。就是一道模板题,模板的名字叫做拓展Lucas。之前和LMY讨论了很久,但就是一个很简单的原理。
BZOJ 2125 最短路。静态仙人掌。我的做法是在最小路径树上跑倍增,最后讨论环的情况。当时思路不是特别清晰,所以考试时没有敲出来。
BZOJ 4565 字符合并。Floj上过了,BZOJ上RE,要到了数据本地又AC。考虑字符合并是可以区间化的。于是设计状态f[i][j][S],表示i到j这段区间消消消之后剩下的状态S。我们只考虑区间长度≤k的情况,>k的一定可以消消消。于是,前导0问题根本不存在,因为对于一段区间只加一两个前导0就会导致非法。而区间长度=k时,就可以合并了。而合并之后又会和前后勾连,所以需要枚举。这里我们只枚举一个区间一个字符的情况,而真正是一个字符的区间的长度是一定的,所以转移就可以保证是合法的了。
BZOJ 1576。之前一直以为要用树链剖分,因为有若干个树上路径修改。今天才发现,不是这样的。把修改排序,依次修改,修改过后的东西叠起来,于是就可以顺利解决了。
11.7
score 阳光长跑。看上去好像好久都没有做过题了……因为知道这道题很虐心,所以最开始分析的很透彻(虽然有一些东西还是没有看见)。打的表很多,而且真的是打表,体育成绩分段表……我把表都叠成了const数组(最后的等级也一样),所以最后实现了比别人短不少(虽然还是有130行)。而题目实在太坑,只给图片表都要自己打。最后有5个小问题:月份表需要空出0号位,长跑测试分男女应该加大括号不然else会跟错if,题目中阳光长跑的记录数m会和我处理记录时的分钟m冲突,if() continue这样的skip应当在读入完毕后执行(特别是多组数据的情况,2月份做IDY的MA时也遇到过这种自作聪明!!!的情况),最后一个比较坑dis单位为km。因为样例是图片所以没有测试样例,如果测试样例后3个错误是很容易能够发现的。而阳光长跑可能是从2017年3月份开始进行的,所以第一个问题可能并不会体现。而第二个问题,确实是语言的常识了。毕竟是清华的校测题,写起来确实很酸爽。
11.9
BZOJ 4033 就是今天的T2。看似是O(n3)的,却是妥妥的O(n2)。处理一条边直接统计它的全局影响就可以很简单。而这确实是一种非常巧妙的思路,整个图的k是一定的当然是个非常重要的条件。但是,如果见多了,这种拆开看每条边贡献的方法就似乎很套路了。像IDY test中那道找k对点的题,还有CDOI中那道线段树合并都是这样。
11.23
NOIP 2017 cheese。官方数据过于水,民间都是80分。关于爆long long的问题,大概可以这样解决:1.使用double进行比较,但不推荐;2.使用unsigned long long,两个数加起来不会爆。故可以先把两个数加起来,如果比右式大就不可,如果比右式小那么三个数加起来都不会爆unsigned long long。后者个人认为是很巧妙的。
NOIP 2017 park。当时因为在T1陷了太久,导致这道题目并没有太深入思考。最后暴力的A*也写错了。当时只有20,A*改对了有30,之后发现A*的状态数只有O(kn),于是可以用WSQ'S TEST里找道路那道题的方法。然而有些点还是有可能反复入队的,因为有0边的存在。再加上A*本身的log,这就会TLE就只有70。于是改成for,dis由浅入深,u再从1到n。可是这样错了,连样例都跑不过。于是又是之前的那个问题,因为有0边的存在,u从1到n可能并不是按照拓扑序的。于是又要拓扑排序,而拓扑排序恰巧就可以处理出-1的情况。之前我判定-1的方法是正图也跑了最短路,找最短路上的点是否在0权环中。最后,要特别注意多组数据的清零。
然后现在是口胡。这道题目在luogu上的难度评级是省选/NOI-,我认为是很合适的。我觉得这道题的出题人应该就是在做A*K短路的时候,想到限制状态数可以更高效,之后再加上0权环使得题目更加充实。源于生活又高于生活,是一道很好的题目。而且,这样的心路历程基本上最后做出来了的参赛选手也经历了。就是hfu说的那种最开始以为是一种模样,之后发现了性质又成了另一种模样,之后又迫于时间空间性质进行了更深入的挖掘与提升。确实是一道很好的题目。
对于这道题目,当时我的A*敲错了,所以说。A*K短路在10月底才敲过,当时还认为很显然考场上却没有想到那一茬,只能说当时还是处理的不扎实。A*敲错了自然就很难发现后面更多的奇妙性质。另外,还是要多测试样例。例如,多次入队如果测样例就会很容易发现。
BZOJ 3110 n个位置,q个操作。操作1:给[L,R]的所有位置都填上一个数v(-n≤v≤n)。操作2:询问[L,R]所有位置上的所有数中从大到小第k大。首先,明确从大到小还是从小到大是非常重要的。因为IDY和MHY那一届的那一道小凸玩矩阵没有大样例坑了很多人,当然这道题目的样例没有那么模棱两可。首先,这道题目很显然是单个数据结构实现不了的。而通常区间第k大采用的是树状数组套线段树,时空复杂度O(nlog2n)。但这道题目有区间修改,就很麻烦(其实应该是可以的)。考虑有区间修改,那么外层用区间线段树?里层?用值域线段树??或许可以吧,反正我不知道怎么做。用平衡树??或许可以吧,反正我不会。反正我觉得套什么都会MLE。此题的方法是外层值域线段树套里层区间线段树,有也可以当作二分答案+区间线段树。而此题还有整体二分的神奇做法。(注:这道题目需要使用unsigned int)
HDU 1394 给你一个排列,你可以每次将a[n]放到a[1]前面,进行n-1次操作后加上原序列一共可以得到n个序列。 求这n个序列中逆序对数最少为多少。因为是排列,所以只需要处理出原序列的逆序对数,每次操作带来的变化都可以O(1)统计。但是HDU有多组数据,导致自己没有1A。
11.24
BZOJ 2125/1665 发现似乎ZKW线段树可以代替priority_queue跑dijkstra而且也很短,但是对于通常的随机数据并不能体现其优秀之处。但是如果图十分稠密则另当别论。
11.25
BZOJ 3262 陌上花开。经典的三维偏序(CDQ???),但却卡了我很久。一维偏序即是排序,二维偏序即是排序+分治就像求逆序对那样,三维偏序即是排序+分治+树状数组,四维偏序即是排序+分治+树套树,五维偏序及以上?bitset+分块暴力乱搞!虽然理论说起来一套一套的,但是写起来就很恼火。首先排序是要三个关键字都要考虑到的,第二维归并的时候用上树状数组,最后再撤销。就是统计左边对右边的影响。
BZOJ 2527 Meteors。经典的整体二分。题目中概念很多,n个国家m个空间站和k场给一段空间站送陨石的流星雨,每个空间站属于一个国家,每个国家对陨石有不同的需求量。问每个国家的需求得到满足的时间点。首先,如果只有一个国家,那么二分答案就可以了。如果有很多个国家,那么捆成一捆二分答案就可以了。但具体为什么要捆成一捆呢?因为时间复杂度其实主要是在树状数组上,时间点不断地滚来滚去大概总的就是O((m空间站数*logm每个空间站在每一层查询一次+n国家数)*logk层数+klogk树状数组的滚动次数*logm单次滚动的复杂度)的复杂度。而如果每个国家依次二分答案的话是一定会TLE的,因为时间复杂度变成了O((m空间站数*logm每个空间站在每一层查询一次+n国家数)*logk层数+k树状数组单次查询的滚动次数*n查询次数、国家数*logm单次滚动的复杂度)的复杂度。优就优在时间点滚动得更高效。但是像如果使用主席树,就不需要整体二分了,时间复杂度成了O(klogm预处理复杂度+(m空间站数*logm每个空间站在每一层查询一次+n国家数)*logk层数),但即使加上标记永久化空间复杂度还是能够达到O(klog2m),在BZOJ的128MB空间下就很难受了。
11.26
BZOJ 1452 ZJC讲的题目。正愁颜色无法区分时,却发现数据范围极小。100个二维树状数组,每个颜色1个。当然也可以想成是二维树状数组套一维数组呢。不知道是否会有人去写什么二维区间线段树套值域线段树的鬼东西。
BZOJ 1901 单点查询区间查询第k大。经典题目,但居然暴力可过。通常做法是树状数组套值域线段树,但也可以值域线段树套区间线段树(就像BZOJ3110那样)。但是后者在这样的环境下则显得时空复杂度均大又冗长难写。
BZOJ 3083 ZJC讲的题目。之前ZJC已经打了预防针,特判确实比较多,但还是RE了一次就是像读优的那样错误。
11.27
BZOJ 2212/3702 线段树合并的优秀题目。值域线段树,因为是排列所以叶子结点一定不会重。要注意中间变量与全局变量的次序,不然就会WA。“好像很久以前有一个神人写过什么证明说n个logn的链(线段树上)合并起来复杂度是nlogn的? ”然后就可以像CDQ那样边合并边考虑左边对右边的影响了。
BZOJ 1014。splay+hash,经典题目。splay还是要比spaly快不少的,这里只要用MOD就会TLE!!!如果改自燃溢出,则base就不能取26了。
UVa 11987 ALMOST-UNION FOUND。刘汝佳蓝书上面的一道经典好题。比并查集多维护了一些东西,就是支持把一个元素从它原有的集合中移除塞到新集合里取。一个直观感受就是,移除一个一定要保证不会对别的东西产生影响。不会产生影响就是说没有点指向它,但既然没有点指向它又该如何实现并查集呢?用虚点。保证实点在最末梢,而只有实点有操作的存在意义。于是顺利成章下来就是了。
BZOJ 2049 LCT模板题目。rotate→splay→access→find、makeroot、link、cut
BZOJ 4241 历史研究,终于把这道积压已久的回滚莫队做了。最终代码不长,但是还是有不少细节当时没有完全想到的。如果考场上遇见这种毒瘤题目还是会先skip掉的。就算写出来也一定要好好验证一番。这种程序验证起来其实不麻烦,生成一个差不多长度为7的序列然后枚举所有情况分辨就好了。要注意的是什么东西该什么时候清零,如果l和r同块的处理,还有莫队的分块方式是1~S-1/S~2*S-1而我平时写分块暴力的时候却是1~S/S+1~2*S,所以要很小心才是。
TO BE DONE: BZOJ 3489
TO BE DONE: BZOJ 3065
TO BE DONE: BZOJ 2599/3697/2152
TO BE DONE: BZOJ 3673/3674
TO BE DONE: BZOJ 2683/1176
带修莫队
11.28
HDU 2136 询问n的最大质因数。呃,这个简单问题……艾氏筛与欧拉筛均可。
11.30
BZOJ 2186 沙拉公主的疑惑。询问N!中有多少个数与M!互质,模质数MOD输出。N,M的规模为1e7,保证M比N和MOD小。1e7很容易让人想到一些比较奇葩的东西,以至于使人偏离了题目本身。N≥M,那么N!一定是M!的倍数。而如果一个数a满足gcd(a,m)=1则有gcd(a+m,m)=1,所以N!中与M!互质的数的个数=M!中与M!互质的数的个数*N!/M!。当时愣是没有想到有这样的一步。然后就可以发现ans=φ(M!)/M!*N!,而φ(M!)所含的质因子就是1~M中所有的质数,于是可以使用线性筛预处理出前一半,递推处理出后一半。对于询问就可以O(1)作答了。但是这样很不优,如果一开始就把所有东西都预处理出来最后却不用真是浪费了。于是可以像测体温那样,汞柱不甩回去就好了。
BZOJ 2956 模积和。式子很好化简,但就是yibingzi模运算。要把思路理得很清楚才是。
BZOJ 2751 容易题。确实很容易,但是Lazer坑我说每个位置上的数必须各不相同……
BZOJ 2296 随机种子。一道非常ZZ的构造题,最开始交不停RE。最后发现有0,改了交上去WA。因为应该输出-1啊。9876543210000000的基础上很容易构造出一个是a(a≤1e6)倍数的答案。
BZOJ 2002 弹飞绵羊。这是一道很好的题目,正解是LCT,但分块也可做。题意是每个点会指向它之后的某个点或出界,单点修改询问单点几次可以出界。首先很明确的是,这是一棵树,如果把界作为一端,把询问的结点作为另一端,询问的就是它们的距离。因为ki一定为正整数,所以一定有解。考虑到这样的距离可以在makeroot再access之后询问子树大小得到,于是就是普通的LCT再维护一个siz即可。我最开始WA得比较厉害,就是没有在树的形态变化的时候适时update,导致信息不实。
另外还可以分块。具体做法是维护每个点至少要几次才能飞到块外以及它会飞向那里。于是单点修改之后,只有它所在块的信息会发生变化,而询问时每个块都只会点一下。但是,中间对于边界的处理还是要小心再小心,要严防数组超级越界的情况。值得提及的是,分块比LCT更快,也就是说LCT的常数确实大得可怕……
12.1
BZOJ 1951 古代猪文。基础板子联盟。模数999911659是个质数,而999911658=2*3*4679*35617,一切就很轻真勒。幂指数%999911658,因为n最多只有sqrt级别个因子,所以可以直接暴力枚举因子,中间使用LUCAS并用CRT合并。外面再快速幂,注意当g=999911659的时候答案一定为0。
BZOJ 3561 DZY loves math VI。n和m只有500000,式子就那个样子就可以了。但是要注意的是,mu有-1所以说不仅要判ans≥MOD还要判ans<0的情况。然而如果中间直接快速幂也会T掉,必须要再开一个辅助数组才行。
BZOJ 3560 DZY loves math V。题目本身不难,但是WA了好久。最后使出超级极端数据才解决问题,有一个地方该%却没有%导致事态十分严重。
Codeforces 837E Vasya's Function。充分理解式子进行化简。还是很巧妙的,如果gcd不等于1就可以直接除,等于1就要进行处理中间适时跳出。但是最开TLE了,原因是中间for有一个判定需要开long long却并没有意识到这么一回事儿。
Codeforces 839D Winter is here。枚举gcd进行容斥。还是要把思路理清楚才是硬道理。
Codeforces 869C The Intriguing Obsession。读懂题目+简单组合数学,桥只能建在三座岛屿之间,很容易想到三部分的桥是相对独立的。之后就很简单了。
To be done:BZOJ 2242 计算器
To be done:BZOJ 2759 一个动态树好题。LCT维护基环外向森林+模方程
To be done:Super Joker II, UVa 12298 母函数+FFT
To be done:BZOJ 2460。线性基+拟阵
To be done:HDU 3949。线性基问第k大
To be done:51NOD 1577。询问区间是否能异或出k。
To be done:BZOJ 2693、3629 累式子题目。
12.3
BZOJ 2391 Cirno的忧郁。确实是一道好题,但为什么没有人去做呢?这道题目要统计的是多边形中离散点的权值和,方法上使用了类似于“多边形面积计算”的方法。找一个原点,和相邻两点围成一个三角,面积加加减减。我们可以预处理出这样的相邻两点的答案数组,这样对于询问的时间复杂度就是O(Q*N)的,而预处理的空间复杂度是O(N2)的,而关键在于怎样预处理。我们可以把点以原点按极角排序,然后定点之后往平衡树中逐渐加入每个点,平衡树是以定点按极角排序的,然后数组中的值就是权值前缀和。
但是注意:边界!!!边界!!!注意边界的处理方法!!!
BZOJ 1610 连线游戏。超级大水题。但是最开始斜率公式居然写错了!!!
12.4
BZOJ 1670 护城河。凸包裸题。
BZOJ 1132 TRO。确实是一道特别特别好的题目。平面上有n个点,要求算出中间C(n,3)个三角形的面积和(n≤3000)。觉得有点像SCOI2017D1T3来着……像这种O(n3)做法麻瓜都知道的题目,一般就是考验你如何捆成一捆解决问题。很好想的是定中间一个点,然后可以按极角排序用O(nlgn+n)的复杂度处理出原来O(n2)的事情。看上去很简单,但中间其实暗藏着陷阱。就是你定点的顺序是不能乱定的,因为定了第i个点之后就要算出第i+1个点到第n个点的对应答案,如果这n-i个点绕着第i个点围了一圈,那还有什么极角排序的意义呢?所以,必须要保证这n-i个点在第i个点的右侧才可以。于是我们必须先对这n个点按坐标排序,定点之后n-i个点还要转移到另外一个数组再排序(或者你不转出去排序两次也可以速度慢将近1倍)才能保证内在的关系。
之后BFK问我,为什么排序的时候必须要保证第i+1~第n个点都在第i个点的某个象限方向?其实中间还是涉及了向量叉积本身的特性,就是绕某个向量点转(0,π)的角度时,我们都认为那样极角更大。而绕某个向量点转(-π,0)的角度时,我们都认为那样极角更小。转0很好解释,但转π就直接导致排序本身所依赖的偏序关系的崩溃,于是一定不能有转π这样的东西存在。
BZOJ 1069 最大土地面积。SCOI2007!就是给定n个点(n≤3000),从中间取出4个点,问其围成的四边形面积最大是多少。如果n<4,则答案为0。如果n≥4然而凸包上的点不足4个此时就比较恼火。但是没有这样的数据,凸包上的点是很多的。于是可以枚举对角线,定一个点,枚举另一个点,中间旋转卡壳得出最优解。但是中间有一个十分重要的细节。最开始交上去WA了,后来交了8月份曾经写过的又WA了,就是以为没有处理旋转卡壳中单调函数中的“平原”部分,这是因为求凸包时的放纵(如果180°也被弃那么就AC了)。之后我企图保留凸包上的平原部分而把旋转卡壳中的判断条件改一下,要么还是WA要么就TLE了。当时十分疑惑,要到了数据研究了很久很久,终于恍然大悟。
如果在求凸包的时候保留“平原”是绝对错误的,首先是旋转卡壳上会出现很长的一段“平原”值需要判断,另外一个却是致命的。如果有两个点的坐标完全相同,那么就悲剧了。求出来的“凸包”很可能在那里就凹下去一坨,旋转卡壳的时候直接就陷入局部最优解了。但如果在排序之后unique一下,就可以避免这样的问题发生。
To be done:BZOJ 4605
To be done:BZOJ 1038
12.4
BZOJ 2829 信用卡凸包。中间有一点非常巧妙,属于小学奥数知识,就是最后计算的时候只需要保留每个信用卡的四个圆心,做了凸包求了周长再加上一个圆的周长就可以了。虽然我可以证明,但总觉得特别玄学。中间我特别关心误差,发现sin在1e-12下出现误差就是说eps取1e-11是更稳的,之后又发现求凸包时的叉乘使得这样的误差变到了1e-11的级别,最终我的eps取的就是1e-10。eps取成什么1e-3固然会产生误差,但eps取得过于严苛同样会导致误差的产生。还有,HZWER的“旋转”算了两次,比较直观但实在复杂。最后,我交上去第一发WA了,是中间输出没有去掉,这种东西一定要严防啊。
12.5
BZOJ 4570 妖怪。题目大意就是,坐标系第一象限有n个点,要求找出一个斜率k,使得过每个点的斜率为k的直线的横纵截距之和的最大值最小。看上去很糊,但我们可以分析一下。对于一个固定的斜率k,每个点的横纵截距之和就是根据这样的直线一条一条确定下来的。而对于某一个点,斜率k对其和的影响也是一个对勾函数。综合下来分析,很容易得知影响结果的只有上凸壳的点。之后路子就多了,可以直接二分答案,判断答案是否可行就是去找是否有一个斜率k使得对勾函数皆在答案之下,就是区间求交辣。也可以三分斜率,中间就是直接计算值。依据都是对勾函数交下来的那根函数是单峰的。当然,我觉得最好的还是直接用性质。因为最终我们要求的是对勾函数的低谷值,要么是凸壳上点的低谷只需要判相邻两点,要么是凸壳上相邻两点。中间的依据都来自定义,切层的哲学。这是一道非常好的数形结合的题目,觉得理解了这道题目,之后斜率优化应该也搞得懂了。
12.6
BZOJ 3503 和谐矩阵。上午考试并没有想出来,但是根据暴力找到了很多种特殊构造的方案,但是开始只有30分。原来是出题人没有写SPJ!!!于是我上网查了一下,很快就写了出来。原来是85啊。之后知道了正解是高消。但最开始是有n*m个元素n*m个方程,交上去BZOJ垫底。后来优化了一下,把高斯约旦改成了高斯回带,就从6000~7000ms变成了400ms。但是还不够!!!发现只需要第一排就可以确定全局所有元素(暴力做法),然后就成了m个元素m个方程,就变成了40ms。同样的方法,BFK20ms,ZJC12ms,而且还有很多的0ms。不知道0ms怎么做……
(注:高斯不回带的效率比高斯回带低了特别多。这里是一千六百元一次方程组,有一千六百个方程每个主元最多出现在四个方程中。如果使用高斯回带,中间就只消了两万多次行,可以当做20*n2。但是如果不回带,则会破坏其稀疏的性质,最后消了四十多万次行,大约是0.25*n3。区别极其巨大,值得注意。)
BZOJ 3506/1552 robotic sort 排序机械臂。一道splay题目,需要考虑的是如何快速找到全局第k大。考虑并没有修改,这个东西可以在预处理出来,O(1)快速定位。而这里既可以是把结点旋上去,也可以是找到再旋,中间逃不掉的是要维护fa指针。注意什么时候应该pushdown,什么时候应该update。
BZOJ 3504 危桥。这道题目非常巧妙,实现很简单,中间的证明比较难。首先,一条无向边如何表示只流一次呢?就是正着一条网络流边,反着一条网络流边。不流就是不流,流一条就是流一条,流两条就等于不流。重点在于,要使得a1~a2间有an条路,且b1~b2间有bn条路。如果直接让s接a1和b1,让a2和b2接t是很有问题的。就是说,如果a1不经过b1向b2流了东西,或是b1不经过a1向a2流了东西是无法判断的。而这样的边如果和a1到b1的边联合就可以合法。一阵YY之后(我也讲不清楚啊),就得到正反跑两次的结论。我觉得BFK说得有理,就是一条无向边“自动”识别的过程。我觉得Mercer说得也有理,就是前一半好桥段后一半坏桥段的自动识别过程。图论的证明总是那么要命。
12.7
BZOJ 1015 星球大战。一道离线并查集,但第一发WA了。很伤心,因为又是从0编号的坑。最开始我是用链表存边,每个时间点按结点加边,跑了1240ms。后来发现根本不需要链表,直接存下来,中间把边重建的顺序sort出来就可以了,跑下来1008ms,再把fread加上就是708ms位居探花。此外,并查集必须要路径压缩+按秩合并才是α的,不然就可以卡成log。
改出一道毒瘤题:如果强制在线,还可做否?
BZOJ 1116 CLO。并查集+无向图,想了很久无果看了题解恍然大悟,这怕又是一场彻悟。联合BZOJ 1529和XGG暑假考过的school,算是明白了。首先,任何一个并查集的联通块都至少有siz-1条边。如果有siz-1条边,就是树形结构;如果有siz条边,就是基环树;如果有更多的边,则会有更多的环。BZOJ1529中每个点都刚好对应一条边,所以一定是基环树,所以只需要破一个环就可以连锁反应,所以说是并查集联通块计数。XGG暑假考过的school,是问每一条边和其一个端点匹配的方案数,那么如果是树方案数则为n(以一个点为根,边都归儿子),如果是基环树则为2(基环内部的方向),如果有更多的边则没有方案。而这道题是没有统计方案,问的是每一个点和其一条边匹配是否有方案。如果是统计,则我们可以思考:如果是树则为0,如果是基环树则为2,如果有更多的边则方案数更多变得难以统计。
改出一道毒瘤题:如果这道题真的统计方案,还可做否?怎么做?
BZOJ 1202 狡猾的商人。一道普通的带权并查集,一定要把权值关系理清楚。像这种题目只要求保存值而不保留关系的,可以尽管的按秩合并+路径压缩。
BZOJ 1370 gang。和NOIP2010关押罪犯很像,一道虚点题目。但还是有坑点。朋友的朋友固然是朋友,敌人的敌人也是朋友。朋友的敌人就是敌人,那敌人的朋友呢?和自己没关系!!!所以说,连敌人的时候,是u~v'和v~u',但连朋友的时候,就只连u~v而不连u'~v'了。实在是一大坑!!!
此外,维护一个有多少个并查集有实点。hzwer是把n个实点的root找出来再sort+unique,而我是直接存一个集合是否存在实点。时间一样,但是内存不同。
BZOJ 3624 免费道路。觉得自己的“一句话题解”写的实在是越来越长了,觉得原来的SIP都没有什么用了。反正这种东西只是写来自己看的……讲正题。这道题目确实非常非常非常好。然而我最开始把题意理解错了。我以为题目是说,道路有黑白两色,选择道路使图联通,并恰好选择k条黑色路径,如果无解输出no solution,如果有解输出选择道路最少的方案。
于是我优先考虑黑色边,如果k还没有填满且黑色边有必要,就选择这条黑色边。之后选取有必要的白色边。最后看,如果不是生成树则输出无解。之后如果发现k没有填满,就随便加几条黑色边。然后……交上去……WA了。发现自己完全错误,抓狂,之后读了又读,终于良心发现。
题目其实是说,道路有黑白两色,请构造一棵最小生成树,使得中间恰好有k条黑色路径,如果无解输出no solution。嗯,我觉得其实两种解释都有道理。就是对于“尽可能少”的理解。既然这样,怎么破?二分?或许可以吧,反正我没有跑过。但这里讨论的是另一种操作。首先,如果优先填白色,则可能导致黑色凑不满。如果优先凑黑色,可能直接导致无解。于是就有了先找必要的黑色边,之后再生成树出来的做法。关于具体的解释,这里说得很好:Clove_unique
一个小问题:到底可不可以二分?(BZOJ 2654 tree)
BZOJ 1854 游戏。这是一道很好的并查集,和前面的BZOJ 1116同属一个系列。这也是每条边和一个点的匹配。一个联通块如果是树,则有一个值无法取得;否则有环,一定可以全部取得。那这样求出每个联通块最大无法取得的值,再取最小值-1就是答案。
但是,如果考到,没有想到并查集也不要灰心。毕竟是匹配,左边放值,右边放边,加点优化,其实还是很可观的。
memory | time | code length | |
并查集神方法 | 950kb | 740ms | 1347b |
二分图匹配笨方法 | 24300kb | 840ms |
1397b |
12.11
UOJ 210 寻找罪犯。2-SAT经典题目。2-SAT就是把若干个不是对就是错的命题当作点,把你的推理当作边,然后缩点之后拓扑得出结果。中间有几个性质:命题不是对就是错,逆否命题等价,推理具有传递性。这其实是逻辑推理的基本原则,只是这里也适用而且很有用。这道题目就是把每个人说的话变成前缀和,例如“此人前i句话全对”的否命题就是“此人前i句话不全对(只错一处)”。若“此人前i句话全对”,则“此人前i-1句话全对”。而这整个命题的逆否命题是:若“此人前i-1句话不全对(只错一处)”,则“此人前i句话不全对(只错一处)”。除此之外,每个人还有一对身份点,表示他是不是罪犯。是罪犯不一定说假话,但说假话的一定是罪犯。所以说若“此人所有话不全对(只错一处)”,则“此人是罪犯”。逆否命题:若“此人不是罪犯”,则“此人所有话全对”。另外,“此人前i句话全对”与“此人前i-1句话不全对(只错一处)”也可以证明第i句话对应的身份点的正确性。前者显然,后者就是因为只能说一次假话。而全图有一对统一的“前0句话全对”和“前0句话不全对(只错一处)”,这两个命题无论哪个正确,都能同样解决问题。而这道题目实际上并没有拓扑排序,因为tarjan得出SCC的顺序本来就是拓扑的。
BZOJ 2742 akai的数学题。昨天晚上考试原题,暴力枚举因子。注意要让因子全都是正的,还有使用long double判定掉精度很厉害,所以要用MOD的inv。
BZOJ 2351 BJOI2011matrix。二维hash,就是两个结点相隔(a,b)它们的base差就是base1a*base2b,如果使用set就有6576ms,而使用%来散列就只有2320ms。
BZOJ 2124 等差子序列。给定一个序列,询问是否存在三个数顺次形成等差数列。最开始根本无法下手。O(n2)的枚举都是天方夜谭,该怎么办呢?考虑到当且仅当对于任意一个数x,x+k和x-k在x的同侧时,才会不存在。再考虑,如果把x之前的数都在值域上点一下,当且仅当是以x为中心的回文串才可以保证所有的x+k和x-k都在x的同侧。这个东西可以使用hash快速判断,对于每一个x要O(n)才能完成的判定只需要O(log n)的复杂度,当然就优秀多了。使用值域线段树很好理解,但中间我又意外踩到了一个盲点。之前我写线段树操作区间从来没有适应性缩小过,之前从未有过问题,但是这一回就是真的不一样了。因为需要准确的区间长度才能算出正确的hash值。而这道题还可以使用树状数组,速度会快很多。
具体说来,是这样的:
空间 | %1e9+7 | unsigned int 自然溢出 | |
值域线段树 | 1276kb | 1800ms | 956ms |
值域树状数组 | 952kb | 644ms | 252ms |
然而这些都不是最快的,952kb 252ms+fread->984kb 180ms。然而最开始却卡了很久的壳,其实树状数组很好实现。只要想到两条线过来只相交一处然后再加上base的幂差就清晰了。但是我还是好好想了一番,充分理解了树状数组的精髓,受到了深深的震撼。最后树状数组还是有2种实现办法的,我认为都很巧妙。如果有空,我是很想写一篇树状数组研究的,当然此外还有并查集、启发式合并和数论反演。
BZOJ 1174 [Balkan2007]Toponyms。在hzwer的版面上,“总输入不超过20000字符”还未褪尽;在BZOJ的版面上,“保证输入文件不超过10MB”却赫然在目。先是MLE到爽,之后则是不停的TLE,最后终于找到了法子:把每个结点的儿子集写成链表。实在有毒!!!
12.12
BZOJ 2741 FOTILE L。这道题目求区间最大连续异或和。主体并不难写,但最开始却RE和TLE了很多很多发。具体原因如下:1.ans+L很可能直接爆int,所以要加long long,注意是要((long long)L+ans)而非(long long)(L+ans)。2.如果只存块到块之间的答案,虽然空间是O(n)的,但时间却可以变成O(2*sqrt*logW)的。必须变成存块到点之间的答案,空间大了sqrt但时间大可减半。3.块的大小分的不合理。当时脑残开成了sqrt(n/log),自己也不知道为什么要这样开。
BZOJ 3261 最大异或和。本身不复杂,是YYR的练手题。但是当时我还会去特判像-1这种情况,觉得烦就整体平移了一位,用效卓著。trie树不写递归版本,效率很高。
BZOJ 3676 [Apio2014]回文串。使用回文树可以很轻松很高效地切掉。中间有一些隐含细节是在写指针版本时才意识到的。数组版本中0号结点既可以是结点又可以是NULL,虽然RE的少了(指针为了躲NULL真是殚精竭虑的),但可能很多细节自己都没有想清楚。回文自动机奇短,使用的性质也令人叹为观止,看来毛子确实太强了。使用的也是后缀自动机的增量法,也使用了fail指针,跳fail的原理也与AC自动机颇为相似。构建函数3个3行,一个是init把ss[0]设做-1(就像manacher的‘+’‘-’)然后把odd(len:-1 fail:odd)和even(len:0 fail:odd)结点建出来,之后是newnode配置len和fail并返回NODE*,最后是跳fail链的getfail,中间的匹配想来也与KMP和AC自动机甚像。主函数是for每一个字符搞增量,对last进行getfail找到cur,在下面挂一个儿子,儿子的len为cur->len+2,fail为cur再条fail的ch。但是要注意,last最开始是even(显然),之后last就是那个儿子。然后fail一定不是NULL,如果实在是NULL那一定对应even。而中间统计了每个点的cnt,然后该点所对应的fail链长度就是新增的回文数。最后统计时倒着for把cnt上传就可以了。
BZOJ 1559 [JSOI2009]密码。51664kb,392ms。AC自动机,alpha小的时候可以直接补全,alpha大的时候还要可持久化数据结构其实也是补全。先把trie树建出,再BFS出fail,之后DP转移可以得出答案。至于答案≤42时如何输出方案,我现在有三种手段。第一种,先把对答案有贡献的状态打上tag,显然≤L*ans,之后再转移一次,只是每个状态是用vector+string存的当前答案。因为空间只有64MB,之前还MLE。之后又WA,才发现方案要求是字典序输出。第二种,从末状态出发,看上一层那些状态可以得到此状态,倒推至终点。第三种,qjx用之常数极大,就是想答案≤42是绝对不可能空出位置的,于是枚举先后顺序得出答案。
12.13
BZOJ 2434 [Noi2011]阿狸的打字机。使用指针,一个struct长得很臃肿。三个链表打头,顺着可以很多东西。一个headf对应它fail树上的儿子(处理出in和out),一个heads对应它trie树上的儿子,一个headq对应它询问的标号和结点。两个数字,fail树上的DFS序in与out(应付查询)。三组结点指针,一个对应自己的26个后继或实或虚(辅助建fail树),一个fail指针(建fail树),一个fa指父亲(建trie树)。顺着字符串来,遇见P记录下当前结点,遇见B向上走一步,否则走到儿子。之后BFS建出fail,再DFS一遍出fail树上的DFS序。再DFS遍历一遍trie树,离线处理询问,使用树状数组维护DFS序,单点修改询问前缀减成区间。
为什么这样是正确的?因为题目询问的是si在sj中出现了多少次。而一个串s的fail所指为其最长的在AC自动机中出现的字符串。而sj前缀的后缀可以对应其所有子串,于是这个问题就可以统计根到sj所有结点在fail树上属于si子树的数量。而fail树每个结点都一定是其子孙的后缀。
BZOJ 3012 [Usaco2012 Dec]First!不过是一个字符串优先级的拓扑排序题,当时只当是水题,没想到却卡了很久。最后在USACO上下到了数据,才发现自己的有向图判环方法是多么哎呀。其实方法很多:1.拓扑排序;2.tarjan;3.区分未访问、正访问和已访问的DFS方法;4.BFS。如果是基环树,则可以跑染色DFS,如果不是还用染色法就实在太蠢了。
12.14
BZOJ 2746 [HEOI2012]旅行问题。AC自动机上找fail树上的LCA。但个人觉得,KMP的fail数组加倍增再hash二分答案似乎也可行,但确乎一定难写。
12.15
BZOJ 3143 [Hnoi2013]游走。最开始看上去毫无思路。但细细一想,无论你的编号怎么配,每条边走的期望次数都一样。于是只要算出每条边,就可以排序之后得出答案了。而每条边的计算由于到达每个点的期望次数相关(注意处理n号点),而每个点到达的期望次数可以使用高斯消元求解(注意处理n号点)。
BZOJ 3036 绿豆蛙的归宿。这道题目本身是一个DAG,而且还保证路径纯正无岔路(一旦有纯粹的岔路,答案就只能是INF了)。有两种做法,一种是正着拓扑排序,算出到达每个点的概率,就知道每一条边经过的概率了。第二种是DFS,算出每个点到终点期望距离,再返回值向上就可以了。
BZOJ 2337 [HNOI2011]XOR和路径。这道题和游走挺像的,只是更像是一道DP题。首先,拆位肯定是首选策略。之后考虑转移,发现只需要f[N][0/1]即可,但是因为本身拓扑关系不明显,而n很小且是期望题,可以使用高斯消元进行求解。而中间在列式子的时候,注意f[1][0]最开始就有一个1,而且每个式子左边都有自己的+1,除此之外还需要判n号结点因为只进不出,而且问题中有自环,degree和matrix中都要判断,不能重复处理。
CF 280C Game on Tree。实现很简单,但确实是一道很好的题目。首先,答案可以通过每个点的出现概率加和得到(期望的线性性),而一个点能够出现当且仅当它之前都没有出现过自己的祖先,再推理可得其出现概率为1/dep,加起来就是了。
12.18
BZOJ 1176 [Balkan2007]Mokia。觉得自己好强大……上午全国来了一群校长,两个胡老师打头阵,特别热闹,好似动物园观光团。天才兽ZJC说,它旁边有个校长盯了它很久,然后说:我们合个影吧!之后天才兽ZJC在机房里有热闹了一阵,特别想带上耳机。YYF说此题可以写树套树动态加点,我居然真的这么做了……但是明显空间严重不足。于是CDQ上阵。
之前一直不会,只会离线的先修改在查询的这道题。做法就是把矩阵询问拆成四个点,与修改混在一起,然后按x按y按opt排序,再for一遍使用树状数组存y的情况。但既然有时间戳,做法当然就不同了。但其实也很简单,不过是在原做法基础上加上CDQ。CDQ按时间分治,每一次处理出mid之前的修改对mid之后的查询的影响,然后递归处理就可以了。
看上去确实很巧妙,又打开思路了。
BZOJ 2683 简单题。和BZOJ 1176完全一样,但为了练手再敲了一遍。觉得真的很巧妙,就是原来区分不出来的现在按照时间戳稳稳地区分出来了。
BZOJ 4753 && UOJ 273 [清华集训2016]你的生命已如风中残烛。总觉得自己很多时候的方法上还是有问题,像这道题目,本身式子很简单(但我还是不会证明),就像NOIP17D1T1,昨天晚上做的SHOI17D2T2那样。还是需要自己构造一些数据,好好观察性质才可以。不管能不能得出结果,这样都可以帮助加深对于题目的理解。有的时候心中会有一种莫名的不快,很多情况下也是这一点做的不到位。像这种题目构造数据很方便,如果不方便的则可以先把mkdata写出来。
12.28
BZOJ 2115 [WC2011]XOR。一道很经典的线性基题目,最后一定是走一条路径,趟几个环这样出来的。再观察性质,发现可以这样做:DFS整个无向图,把所有返祖边(前向边)构成的环加入线性基,然后把DFS树上从1到n路径的异或和在线性基中求一个最值就可以了。当然,随便找一条路径也可以。为什么呢?考虑到一定是有一条主路,然后转几个圈这么出来的。从主路到圈上,一来一去路径可以抵消,但是就多异或了一个环。至于主路如果选错了呢?也不影响,就是选出的主路和最优的主路是一定有环的,把这个环异或了,相当与就变了道。不过,这只适用于无向图。如果是有向图,到底该怎么做呢?
1.2
BZOJ 4289 PA2012 Tax。经典的最短路建图,考虑按边新建图。这样,设置一个源点s,连向代表1出边的新点,代价为原边代价。设置一个汇点t,代表n入边的新点连向它,代价为原边代价。考虑途中的一个点u,就是代表u入边的新点一一连向代表u出边的新点。这样连边会炸,于是考虑简化过程。好比2-SAT前缀和压缩,这个地方代表u出边的新点间都连上了一些转移边。而代表u入边的点只需要连很少几条边。由于是无向图,可以直接连接其反边。若是有向图,则需要再二分一下。最后跑出最短路即可。卡常数打榜。
BZOJ 4152 [AMPPZ2014]The Captain。这题真卡SPFA,那就老老实实用DIJKSTRA吧。这道题以前做过,边看似是O(n2)的,但其实只需要勾出xy的经纬脉络就可以了。连接x排序与y排序上相邻的点,这样任意两点的到达都可以拆成这样的若干部分。边就只有O(n)的了,就过了。这种题目就是不能老老实实建边,就只有靠这样的简化手段了。卡常数打榜。
1.8
BZOJ 4553 [TJOI&HEOI2016]序列。好久都没有刷过题了啊!会考弄的人心塞塞,生物还不知道能不能过……这道题目早就知道是分治,却一直不知道做法。有一个很显然的事实是,如果CDQ分治一定是按位置分治,之后我就不知道了。
于是中间有一个很重要的性质:一对i,j,i
这道题目主要是那个性质比较卡人(其实也很好发现的),如果能够真正深入思考应该还是可以发现的。
还有,“自我”卷积也类似的,分治+FFT。如此看来,分治的作用还真不少。不过,其实就是三维偏序啊。
BZOJ 4237 [JOI 2013~2014 春季training合宿 竞技3 PO姐上传] 稻草人。这道题XGG很喜欢,已经两次考过了。CDQ分治,一个点前缀矩阵单调栈可以使用分治+单调栈统计答案。
BZOJ 4816 [Sdoi2017]数字表格。最开始只当是一道诱人的数论水题去做,做完第一遍,才发现不对,样例跑不出。原来题目要求的是大π而非Σ,于是划下去就懵逼了。当然,如果想到用T整齐带入,式子也不困难。当时思考未深入,浮于浅表,便未想出来。而这道题目好像是T1的样子……之后就那个样子做。但是需要注意:中间乘逆元明显可以之前预处理好,如果中间每次log去算,则是妥妥的大常数nlog2n。第二,mpow(a,b)中间long long的a要%MOD,而long long的b要%phi(MOD)。第二点很隐蔽,之前根本没有想到,也可以算是思维死角了。
1.9
BZOJ 2049 [Sdoi2008]Cave 洞穴勘测。一直听说这题可以用并查集,但是当时学LCT写的并查集却是妥妥的错的。很明显使用并查集不能路径压缩,那这样如果要连一条边,而两个点都不是根,应该怎么办?我当时过于naive,认为直接把两个集合的根并在一起,并存下来这是u和v媾和的结晶。但是,如果说u和她的根分了家,那这条边作为家产就是不好分的了。怎么办?并查集其实也可以makeroot啊!我之前认为,如果加上siz数组会稍微麻烦一点,但复杂度有保障。但是,LCT为什么不按秩合并呢?因为颠来倒去,siz不siz都已经没关系了。如此说来,并查集其实也是O(nlog n)的,甚至更大,因为可卡而且很容易卡。而LCT是一条一条链跳的,均摊下来O(nlog n),只是常数很大。并查集这样的问题算法,在随机数据下表现强劲,用来打榜确实是不二人选。
BZOJ 3237 [Ahoi2013]连通图。这道题是一道线段树分治,因为分治方式很像线段树而得名。中间需要用到待撤销并查集,如果使用二合一并查集就会有很优异的效果。一条边能够被扔进线段的一边,一定是在线段的另一边有阻隔而在这边没有。按照这样做,效率挺高的,好写好调。但是,这么一道好题怎么能只这样做???随机乱搞也是可以的!!!
就是说,DFS树上割了若干条边,什么情况下是有效的?就是一个点的父亲边被割了,它的子树中连向外面的返祖边也被割了。于是,自然而然的,一种做法就出来了:给所有返祖边赋一个随机数,给一个点的父亲边赋它的子树中连向外面的返祖边权值的异或和。这一点使用DFS很方便可以实现,同理BZOJ3563和3569都可以这么“水”掉。而著名的“共价大爷游长沙”也很类似。
BZOJ 3569 DZY Loves Chinese II。真的,加个线性基,随机化也是AC,还可以在线询问!更不可思议的是,这真的就是正解!
BZOJ 3563 DZY Loves Chinese。同上。但是,此题因为也异或了k,于是可以乱搞一下……就像XGG的jigsaw一样……看来后人造的孽前人都干过啊……只是,为什么我WA了……
1.10
BZOJ 3110 [Zjoi2013]K大数查询。写的我“神清气爽”,打算专门写一篇blog以记事。
1.11
BZOJ 1492 [NOI2007]货币兑换Cash。终于学会了斜率优化DP……截距max取上凸壳,上凸壳的k递减;截距min取下凸壳,下凸壳的k递增。如果加入点的xy坐标有相对顺序,则可以使用单调队列,否则需要使用CDQ分治归并或平衡树。如果查询的k有相对顺序,则可以使用单调队列,否则需要二分斜率。这道题目可以使用CDQ,很明显一段区间先处理左一半,考虑左边对右边的影响,再处理右一半是正解。影响,就是左边搞出一个上凸壳(因为截距要取max),右边在上面找斜率。
O(nlog2n)的做法很naive,就是左边按xy排序后弄出上凸壳,右边按斜率排序后单调指针扫描或是二分斜率。但是,O(nlog n)也可以啊!就是最开始整个序列按照斜率排序,这样在solve(lf,rg)时整段区间就是按斜率排好序了的,而最后返回的是整段区间按xy排好序的。把(lf,mid)和(mid+1,rg)的点分离出来相对顺序不变,然后solve(lf,mid)。返回时左一半按xy排好序,可以直接搞出上凸壳,而右一半还是按斜率排序,于是可以单调指针扫描。然后solve(mid+1,rg),此时右一半也按xy排序,于是可以归并得出整段区间。中间f[i-1]到f[i]的转移在最下面lf==rg处执行。
但是,我最初交上去却被卡了。调试了半天,原来是EPS的问题。eps的问题出在上凸壳弹点和单调指针扫描上,从根子上说就是相等可以被容忍。但还是很迷,eps=1e-11被卡,eps=1e-9AC……
BZOJ 2223 [Coci 2009]PATULJCI。这道题目在多校集训时考过,n=300000当然不能分块,但当时仍讨论出了4种做法。
法1:我当时AC的方法。使用一个主线段树,存储的是MODE信息。另外有值域棵线段树,用来进行核查。时空均为O(nlog n)。常数大,125492 kb,1924 ms。
法2:考虑到两个线段树都不需要建出来,主线段树可以使用分治模拟,值域线段树也可以直接使用vector来进行二分。时间O(nlog n),空间O(n)。跑得飞快,RANK 5(RANK 1是mcfx卡不过)。5628 kb,496 ms→344 ms!不过,直接使用数组代替vector,看上去会更快,但实际上……
法3:上述的做法还是不够巧妙。考虑到一个区间如果有答案,那么在区间中随便抓个数是答案的概率是大于一半的。随机取个k次,用vector检查,那么找出来的概率就很高很高了……我取k=28的时候就可以过,这样时间O(nklog n),空间O(n)。虽然n达到了300000,但是很多情况下k都没有达到30,常数还小,其实挺快。5264 kb,572 ms。
法4:但是传统的做法未必不可行。使用非常套路的主席树,查询时往多的那一半走就可以了。时间O(nlog n),空间O(nlog n)。72544 kb,680 ms。
1.12
BZOJ 4753 [Jsoi2016]最佳团体。JSOI一共分两轮,第一轮3道题,第二轮8道题,这是第一轮第一题……典型的01分数规划,二分+树DP,确实是送分题啊……
BZOJ 1334 [Baltic2008]Elect。我觉得题意很迷,按照我的做法,求出来的是“有n个物品,选出一个集合使总权值最大,使得删去任意元素后该集合的权值和都不超过一半”。这当然很简单,枚举中间最轻的一个元素,只要其他的都不超过一半就好,于是是一个普通背包。但是,考虑到背包中根本就没有超过一半的,于是可以只取一半做。
BZOJ 2794 [Poi2012]Cloakroom。这道题看起来很像偏序,用分治吗?然后呢?寻觅未果,于是另觅它途。使用DP,但状态的定义很将就。f[i]表示恰好凑出权值i的物品的b最小值最大是多少。于是这个只需要按a排个序,然后逐个加入更新就好了。思路很巧妙,跟编号最大生成树统计边区间联通块数颇有异曲同工之妙,之前BFK讲了一道查询区间能否异或出k也颇为相似。
BZOJ 4446 [Scoi2015]小凸玩密室。此题极妙。考虑最后的过程是:点亮一个点,点亮它的子树并点亮它的父亲,点亮它的兄弟,点亮它兄弟的子树并点亮它的爷爷……最后只用到了g数组,但求g数组需要f数组……状态的定义是可以像积木一样拼在一起的,说是基于未来状态也无不妥。而这一道题目的难点就是状态定义。另外,完全二叉树和“联通子树”的性质需要选手充分挖掘,考虑出整个过程并分阶段。还有,处理出DP数组之后枚举每一个点统计答案的方法也很巧妙。我的DP中有很多的辅助数组,常数比较小,但是中间易混淆的地方稍微有点多……之前调的时候很JIJI,大概是3个地方:1.int*int→long long的标记;2.到底是i<<1还是i>>1;3.到底是LS还是RS。看的时候一晃就过去了,还会以为自己是正确的。事实上,因为这道题目的体系比较复杂,我有这几个错的时候对拍都可以过……事实上,数据也能过很多组。还是要提高代码的验证能力啊。
BZOJ 1864 [Zjoi2006]三色二叉树。06年的大水题,转移都是枚举出来的(但是杂色和杂色可以在一起要不是样例良心就挂了),数组都懒得开,直接“typedef std::pair
1.13
BZOJ 3167 [HEOI2013]SAO。好SAO啊~~~f[u][i]表示u的子树中u排第i,合并的时候枚举新加入子树有多少个点排u前,多少个点排u后,之后加上前后缀和跟组合数就很优秀了。而像这种强制必须合并的,必须要另开一个数组,而且用之前应该清零而非把值继承过去。卡一卡,发现只需要维护前缀和,减一减就是后缀和,当然还是要注意不能搞出负数。此外,这道题似乎输入规模过小,加上fread反而变慢了……
BZOJ 1131 [POI2008]Sta。有容乃大,无欲则刚。这道题目显然很简单,于是尝试了新花样。先对树进行一次DFS,按照DFS序给结点重编号,这样之后的操作就可以不再递归了,呃卡常数。其实可能是因为我加了fread而别人没有加……渐入癫狂……
1.15
BZOJ 4872 [Shoi2017]分手是祝愿。当时根本就没有想这道题,只觉得这道题好神啊~但现在一看,转念一想,呀这不是线性基吗?显然,n个位置,碰每个位置就对应了该位置的线性基元素,这显然是线性无关的。要把所有1变成0,其实就是从高位到低位(或是从低位到高位?)用线性基异或出来,这贪心显然正确。于是再想想,碰了一个位置,线性基只会多一个或是少一个元素,最后空了就是答案。这就很优秀了,这道题目100000之大不能用状态压缩DP来搞,而线性基中的元素个数就是最少需要的次数,乱糟糟的k也迎刃而解。注意在求解的时候,区分t≤k与t>k的情况。
BZOJ 4517 [Sdoi2016]排列计数。一道很简单的题目,错排递推+组合数递推。
BZOJ 4824 [Cqoi2017]老C的键盘。LRD说这道3167的弱化版是D2T3……
BZOJ 4027 [HEOI2015]兔子与樱花。一道不错的树自底向上贪心,犹记得上一个是IDY的最少选取多少个点覆盖树上选定所有路径。但是这个的理论还是有一点不同,主要还是基于整体的无后效性。很优秀的,但看上去也会有那么一点点玄学。
BZOJ 1060 [ZJOI2007]时态同步。其实想法很简单,但是往往容易为人所忽略。因为根要到所有叶子距离相等,就是说整棵树所有子树都满足这种情况。于是考虑访问u时,儿子v都已经相等了,而u要保证一致,就只有修改(u,v)的边权,很明显u中最深的不动,每条边加上Δ就可以了。而这道题目如果两条边合成一条,则刚好块快了三分之一……
1.16
BZOJ 3162 [2013湖北互测week1] 独钓寒江雪。这道题目本来很优秀,让人心生仰慕之情。然而,交上去,就爆栈RE。反反复复修改,本地只需要16Mb的栈就能过,难道是BZOJ只开了8Mb的栈么?啊啊啊啊啊。IDY说考试的时候肯定不会这样的……
而这道题目到底是要我们干什么呢?求一棵无根树上本质不同的独立集的个数,树的形态相同而树的独立集不同。如果不要求本质不同,那就是非常经典的简单DP。如果深入考察“本质不同”,会发现,除非一个结点几个儿子的子树长得一毛一样,才可能出现方案不同而本质相同的情况,这个显然可以使用hash搞定。如果进一步再一步然后然后考虑,就会发现这和“n 种物品,每种物品无限个,求取m 个的组合数”颇有异曲同工之妙。但是,这个其实是有根树同构。不然,“除非...才可能...”就是完全不成立的。但这其实也拦不倒我们,因为一棵树所有直径的中点都是一定的(反证法易证)。就把这个中点作为根好了。如果是一条边呢,就只有多枚举一下了。
这道题目颇为巧妙(但可能也是新套路题)。中间那个“异曲同工之妙”和“无根有根”是比较那个的,如果事先没有接触确实会特别恶心。但这道题目的10%是无本质相同情况,20%是一条链。如果没有能够想这么多,30分其实还是稳稳的。
BZOJ 3160 [2013湖北互测week1] 万径人踪灭。做完“独钓寒江雪”后打算顺带做的字符串题目。给你一个只含a和b的字符串,求位置和字符都关于某条对称轴对称且不能是连续的一段的子序列的个数。稍微想一想,会发现“且”字后面那一坨根本不成问题,求出来“没且”的减去“带且”的就可以了。“带且”的就是回文串,重新复习了一下manacher。“没且”的只需要求出每个字符两端位置相对的且相同的字符个数,这个使用FFT易解。而仅一次FFT和DFT是完全可行的,但需要玩转1和i。
1.17
BZOJ 4319 cerc2008 Suffix reconstruction。当时NOIP前考过,犹记得LKQ说自己写的很优,一个trie+splay,居然是O(nlog n)的!!!但是,其实因为sa和rank数组都已经得到,每个位置字符的大小关系已经可以得到(若rank[sa[i-1]+1]
BZOJ 3998 [TJOI2015]弦论。他们都说是后缀自动机模板题,但是为什么统计子串数目就要那样统计啊?搞不懂搞不懂搞不懂!!!
BZOJ 3325 [Scoi2013]密码。和BZOJ 4319可以相得益彰。给你pal数组,让你恢复出字典序最小的串。题目保证合法,就不用考虑那么多,这个可以模拟manacher的过程,但是每个位置可能有多个取值不合法,需要使用bool数组记录。
1.18
BZOJ 4902/UOJ 299 [Ctsc2017]游戏。D1T3……不过,标程的做法确实很符合。因为是维护一个集合,加一个或删一个元素,set+线段树辅助处理,就像YALI GUOQING2 T3容斥或是BZOJ 3991 [SDOI2015]寻宝游戏(XGG TEST)set维护DFS序那样,每一步都很惊心。但是,我写的是另一种做法,翻UOJ统计的时候发现的,非常巧妙。可以说是DP,但又不是DP。状态的定义很微妙,很容易混淆,最开始我也理解错了。使用这样的做法,直接使用线段树维护,每个线段使用2个2*2Matrix存状态,最后取根就可以了。概率论实在是一个非常奇妙的东西%%%
1.19
BZOJ 2007 [Noi2010]海拔。平面图转对偶图,和BZOJ 1001很像。但是要注意方向,分清楚谁是谁……不然也不会多调一个小时……另外,N*N*dis虽大但N*dis很小所以不需要long long。还有,我只开了1000050条边的空间,但最后有1002000条边……啊啊啊啊啊。DIJKSTRA340ms,网上有人的SPFA和这个速度相当。但是我写出来(加了双端队列优化)还是跑了3400ms,不加优化就是8000ms……不加优化的SPFA就已经TLE了。
1.20
BZOJ 1823 [JSOI2010]满汉全席。不知道为什么这道题A得这么轻松愉悦,4945却到现在还没有A……就是裸的2-SAT,记得当时NOI考完之后,蒟蒻liu_runda和神犇anantheparty都一致表示学习了假的2-SAT,n=50000是什么鬼,构造方案是什么鬼。估计他们都被蓝书骗了,蓝书上的2-SAT是O(NM)的暴力搜索回溯,和这道题的N=100&M=1000也挺配的……
BZOJ 1997 [Hnoi2010]Planar。带Hamilton环的平面图判定。
法一:很容易想到是一个大环上若干线,在圆内或圆外,总之不能相交。如果两条线在圆内相交,那么也在圆外相交。使用2-SAT来判定当然是可以的。
法二:2-SAT显然不是最优的,稍作观察,可以轻松发现所连的边都是双向边,最后也只需要判定两点是否在同一个联通块内,这就是关押罪犯经典并查集了。
法三:但是问题的实质我们还没有发觉。这其实是二分图判定啊。两点在同一个联通块内,就是说碰上了奇环就挂了,于是只用DFS就好了。
但是,因为有“平面图→m≤3*n-6”的美妙性质,导致我很多组数据如果m不达标就直接输出NO,下面2*m+n个数就这么被抛弃了……想当年我做IDY的CRT也是这样,也是错误查了半天查不出来……还要注意的是,并查集merge的时候必须判已经同集合的情况,不然会无情的带来环……
BZOJ 2199 [Usaco2011 Jan]奶牛议会。看到这道题,以为和满汉全席一毛一样。然而不是,因为这个输出方案有“?”,O(n+m)的tarjan只能判可行性和找可行解,但这个地方要判可行性还要判断每个位置选择的必要性,就非得O(n(n+m))的暴力DFS不可了。如果像Hzwer那样没有剪枝最后还for一遍,要跑160ms。如果加一个剪枝(如果对立点成立则不可行),最后也不需要for,就变成了68ms。如果加上一个栈变成撤销操作,在这道题目中反而更慢了,变成了72ms。网上有人说,如果先tarjan缩点然后再暴力DFS会更快,果然只跑了44ms。但其实复杂度本身没有变,只是常数小了一些而已。
1.24
UOJ 317/LOJ 58106 [NOI2017]游戏。BZOJ 4945没有SPJ,问题很严重。这道题目当时满怀憧憬,觉得自己可以1A。结果发现,恰恰相反,很久很久才完全调出来。最开始的问题有:
1.字符串长度即2-SAT命题个数n≤50000,但其实有2*n个点,有关图的数组都应该开2*N的空间。我的dfn、low和belong数组就只开了单倍的,大数据直接RE。
2.每一组不同的串check开始时,边集需要清空。多组数据的好习惯。
3.2-SAT建边的逻辑存在着问题。这个问题藏的很深,也是最后才发现的。就是说,当a选x时b必须选y。我当时很脑残,当且仅当条件和结论都找得到对应点时才连边。但是,其实当条件找得到而结论找不到的时候,条件就是一定不能成立的,需要连向其反点。
4.tarjan的时候,我的点是从2编号到2*n+1的共2n个点,但当时信手就来,从3开始枚举……
5.2-SAT最后构造方案的时候,比的是拓扑序就是比belong,dfn有个什么用?
我写图论题经常都会挂,很大程度上是不够熟练。但同样的还是自己的思维常常不够严谨,写东西不过脑子。这个,在一定程度上可以通过改良习惯达到,例如说1和2。多理一理,多静态分析一下。而4和5则属于不过脑子的更为典型的例子,常常神出鬼没而无踪迹。但如若足够聚精会神,也会是这样的么?而第3条,这种东西确实不容易想到,但多见见就可以更加老成。
1.25
BZOJ 4669 抢夺。这道题目最开始并没有完全理解费用流的做法,其实就是找到最小的T,使得sigma(T+1-dis)*flow>=k。这个东西经过转换后,时间对应费用,容量对应容量。因为实际最后的方案是一波一波的送的,然而这个东西并不需要二分。直接求就好了。有一处TLE很久,就是因为对比的是dis[v]而非dis[t],就这么错了。
BASHU 5402 [2018清北模拟1] 变量。最大权闭合子图的完全版,两种选择。代价连源汇,点与点的代价的意义是此此彼彼的情况。像文理分科、最大收益等一系列题目其实所有点都可以看成普适的本质相同的选择,而不应该独立分什么设备与任务之类的东西。最开始想不编译1A,无奈队列q和条件数q重合,f没有定义,mxflow()不同于flow()。改正确之后,就TLE了两个点。多番寻查无果,将当前弧优化去掉才终于AC……迷……
未完待续……