10.29
WZOI第一次模拟赛, 2h -> 0
卡第一题, 现在头晕中. 思路错误, 很快的得到了题意, 对斐波那契数列取模. 然后用特征方程搞出了递推式, 然后发现n>=20后的情况, 尝试对无理数取模, 然后各种头晕.
*这是NOIp, 不是CMOp, 怎么会考这么蛋疼的东西. 找时间重写吧, 限时2.5h. -> 应该往周期数列的方向上想
*感觉现在需要系统复习, 又是瓶颈状态
10.30
调教Ubuntu in VMware, TeX中文无能
姜碧野论文<SPFA算法的优化及其应用>, 学习差分约束系统
*还有两种优化SLF和LLL, 真心觉得不如打dij+heap
butter, 复习SPFA.
*关于数据结构的整理
(1)邻接表 first/next/u/v/w/Cnt -> addEdge()
(2)SPFA d/q/inq
(3)初始化 first/d
*没有考虑双向边, 不可达的情况. 在敲代码之前应尽可能完善算法.
poj3259[DEC06, Gold, SPFA找负环]
(1) BFS做法
数组count[]记录每个点的入队次数, 由定义易知, 若count[i]>=N, 则图必然存在负环.(<算法之道>上有个很好的例子)
*标程直接按照Bellman-Ford的定义做, 复杂度O(NM). 网上的一次BFS的做法是错的, 比如两个强连通分量的情况:
1
6 4 2
1 2 2
1 3 2
2 3 2
4 5 2
5 6 10
6 4 10
*因而N次SPFA的效率O(kNM)可能不如裸的Bellman-Ford O(NM); 更好的做法是Tarjan+SPFA, 即只对每个强连通分量进行SPFA, O(N + kM)
*优化:
1) d[]可以初始化为0, 速度比(3)要快
2) 入队次数不超过2(M+N), 可能错误
(2) DFS做法, WC09姜碧野论文涉及, 实现无能.(网上的做法又是错的)
(3) Bellman-ford, O(VE)
三重循环, 对每条边更新V次, 效果好于(1)
*SPFA找负环, 利用vis标记每个点是否被访问过, 仅对当前未访问的点进行SPFA, 这样的话效率应该高于O(VE) //期望情况下
10.31
poj1201[差分约束系统], 25min, 1Y //参见WC06冯威论文
关键在于建模, 令d(i)表示0..i的整数个数, 可得
d(b) - d(a-1) >= c_i
d(i) - d(i-1) >= 0
d(i-1) - d(i) >= -1
即
w(a-1, b) = c_i
w(i-1, i) = 0
w(i, i-1) = -1
按照定义, 求整数个数最小值, 即求SPFA最长路.
*注意更新最小标号idS, 最大标号idE, 第二类边要对1..idE的情况赋值
*关键在于找出差分方程组
http://blog.csdn.net/kk303/article/details/6864199
*一般的解题步骤: (1)建模 (2)设计数据结构 (3)写出大致流程
po3169[差分约束系统], 35AC, 3WA
(1) 建模
题目中给出两种边(a, b) , d
对于第一种, (a, b) >= d
对于第二种, (a, b) <= d, 即(b, a) >= d
*SPFA求最短路, 还是最长路, 由不等号方向决定
(2) 讨论各种解的情况
1) 正常
2) -1, 存在负环
3) -2, 无法连通
*对于负环, 小范围Bellman-Ford(多进行一轮松弛操作), 大范围一次SPFA(count[i]>=N)
*各种字母打错, 变量打错 -> 对于点, MAXn; 对于边, MAXEdge;
东方幻想乡Stage2, P4, suika[分层图最短路+SPFA], 1h
(1) 建图
1) 点从奇时刻到偶时刻(U,U'), 从偶时刻到奇时刻(U',U)
*需要注意黑洞停留消耗体力s[U], 白洞不消耗
2) 边, 两种情况
A. 端点颜色&重量相异(正负号取决于题意)
奇时刻到偶时刻 (U, V') = w(U, V) ± delta
偶时刻到奇时刻 (U', V) = w(U, V) ± delta
B. 端点颜色相同/重量相同
奇时刻到偶时刻 (U, V') = w(U, V)
偶时刻到奇时刻 (U', V) = w(U, V)
(2) SPFA最短路
*注意读题(题意/算法流程/数据结构)
*Nettle标程的做法, 规定2*U为偶时刻点, 2*U-1为奇时刻点, SPFA起点由起点状态决定. 可以避免建图时的讨论.
*算法三依旧理解不能.
NOIp09, trade
(1) 传递闭包+枚举, 40
1) O(kN^3), 利用邻接矩阵更新连通性
2) O(N^2), 对每个点找最大旅费, max{w[i] - min{w[j]}} ((j,i) (1,j) (i,N)连通)即为答案
(2) 两次SPFA维护连通性+枚举, AC
1) 从起点1开始SPFA, d[i]表示(1,i)是否连通;
A. 对于正环的处理
按照定义, count[i]>=N则不再入队.(这样70, 利用r<=2*N不再入队可以AC)
B. 记录遇到的最小价值Min{A[j]}
2) 从终点N开始SPFA, 将之前的边反向(添边时使用last和prev数组, 替代first和next数组), 维护连通性
3) 枚举min{A[i] - min{A[j}}, (j,i)连通, 1<=i<=N的最大值即为答案.
*题解给出了两种做法
(1) 求强连通分量缩点, 转化为DAG, 然后求解
(2) d[i] = min{d[i], d[j], a[j]}作为松弛操作, SPFA
SPFA专题结束, 明天开始Tarjan和dij+heap
11.1
agrinet[Kruskal], 20min, 复习Kruskal
11.2
Tyvj, Sept09, P2[Kruskal + 并查集]
需要理解Kruskal的过程, 做法如下:
(1) 间接排序(边集数组)
(2) 按照Kruskal, 从w[i]最小的边开始统计,并查集维护联通性
p[x] = y;//并集
num[y] += num[x];//统计每个集合的点的个数
maxe[y] = max{maxe[y], maxe[x], w[i]};//维护每个集合的最大边
ans += (C(2,num[x]+num[y]) - C(2,num[x]) - C(2,num[y]) - 1) * (maxe[y] + 1);//统计没有联通的边
*没有间接排序WA了一次,可以通过小数据检验(比如深度不同的树、链)
*各种卡long long, 可以计算最大值为10^6C(2,10^6)
-> long long的类型转换, long long类型的计算中, 数字必须标识ll, 否则会导致计算错误.(也就是说可能爆int范围的地方都要用long long)
-> [by gXX] 可以这么分析, (long long) = (int) * (int) / (int); 于是中间的寄存器会挂掉
*深度大于1的树的生成 by Ylen
和深度为1的树的做法相同, 然后记录叶节点, 对叶节点随机伸长
NOIp10, P3[并查集]
*需要明确并查集能干什么, 并查集可以合并, 但是不能隔开 -> 把分隔操作转化为合并操作
(1) 间接排序(边集数组)
(2) 利用sep[i]记录i的敌人, 对于(u,v)
i) sep[u]存在, 那么merge(v, sep[u]) //u的敌人们是朋友
ii) sep[u]不存在, 那么sep[u] = v//v是u的敌人
v同理, 遇到find(u) == find(v)的情况, 直接输出答案即可
*需要注意特判冲突的情况, 不妨用flag标记, 若没有输出答案, 则输出0
王晓东练习题, 序关系计数[DP]
f(i, j) = (j+1) * (f(i-1, j-1) + f(i-1, j))
f(i-1, j)很好解释, f(i-1, j-1)解释无能
[状态]f[i][j]表示i个数加j个小于号
*Covi给出一个结论, 禁止小于号加在一堆等号内部, 证明无能 -> 在zjy的提示下解决了
*注意到序列中已添加的数的值是不变的
i)f[i-1][j]的话, 已有的数被分成j+1组, 显然每组只能添加1个等号
ii)f[i-1][j-1]的话, 已有的数被分成j组, 因为要添加<号, 所以只有(j-1)+2=j+1个位置可以(即每组的边界)
Contest OPEN11 Silver, llang[并查集]
(1) 读入分别以 奶牛 和 语言 为关键字, 用邻接矩阵存储(这里必须用到vector)
(2) 合并说相同语言的牛, 得到m个集合, m-1即为最少数量
(3) 遍历N个点, 若该节点所在集合未被遍历, 则标记遍历并输出
*vector的用法: 非常适合稀疏图的邻接表的数组实现
(0) 声明变量: vector<int> A;
(1) 加入元素: A[i].push_back(elect);
(2) 获取某列元素个数: A[i].size();
(3) 获取某个具体元素: A[i][j] //0 <= j < A[i].size(), 注意范围
还有一道kruskal和两道tarjan以及dij+heap
11.3
NOIp07真题, 3h, 300
P1: 模拟, AC
P2: 字符串, AC
利用flag表示是否输出(仅标记), 然后Expand函数三重循环即可.
*考虑这种情况1-2-7, 以及A-B
P3: DP, 90(本地压四位后90)
[状态] f[k][i]表示当前行长度为k, 行首编号为i
[方程] f[k][i] = max{f[k-1][i+1] + A[i] * 2^(L-k+1), f[k-1][i] + A[i+k-1] * 2^(L-k+1)}
[初始化] f[1][1..N] = 2^L * A[i]
*变量打混, 务必静态查错
*高精度写挂
(1) 进位
(2) 输出0(去掉前导0的时候, 保证len>0)
*print可以特判len<0输出0
(3) 双目运算符必须const, 这是一个很好的习惯, 避免值发生不必要的改变;
*返回的bign尽量新建.
*最大测试点, 本地0.9s, RQ0.4s, Tyvj0.0s
P4: Floyd+乱搞, 50minAC(计时赛无分数)
(1) Floyd求任意点最短路, 记录最大值(即直径)
(2) 对d(i, j)=直径的边, 求路径
(3) 对于每个直径, 求出它的所有路径, 然后对每个路径求其他点到此路径的最大值(dist操作, 某点到此路径的最小值)
*点的情况需要特判
*注意区分最大/最小值, 这题考的就是对于抽象模型的理解能力
*有线性时间做法
东方幻想乡Stage2, P3, 60栈崩溃
11.4 & 11.5
叉姐模拟赛, 140/300
P1: 字符串处理, 卡通配符含义, 30
(1) 读入, 可以利用数组+标记字符 或者 vector
for (int i = 0; i < n; ++ i) {
begin[i] = sumLen;
scanf("%s", str + begin[i]); //给出字符串首指针
len[i] = strlen(str + begin[i]);
sumLen += len[i];
}
*str记录字符串, begin记录起始位置, len记录长度
*vector必须手工转换, 不能直接利用scanf读入
(2) 标记*位置(初始化为strlen(p), 注意没有*的情况)
(3) 从起始位置扫描一次, 区间[0, pos)
从终止位置扫描一次, 区间(pos, len-1]
P2: 最大带权生成树, Kruskal变种. 写了一个生成子集, 40
[AC做法]
(1) 判断无解[邻接表 + BFS]
*注意变量名
(2) 边i的权值为w[A[i]] + w[B[i]], 根据度的定义容易得到.
之后套用Kruskal, 降序排序即可.
[40%做法]
(0) 判断无解
(1) 位运算生成子集(N <= 20) -> 亦可DFS生成C(N-1, M)集合
(2) BFS验证连通性
(3) 计算权值
*一开始看错范围, 认为必须用O(N)算法, 然后不考虑排序. 权值最大 -> 度最大, 贪心无能.
P3: 动态规划, AC
利用恒等式\sum{x_i * x_j} = 1/2(\sum{x_i}^2 - \sum{x_i ^ 2})
可以通过观察, 或者数学证明最值只在极值点取到.(60%算法, 直接枚举)
因而要求\sum{x_i * x_j}最小值, 即求\sum{x_i}^2的最小值
\sum{x_i}的最小值, 可以对所有数进行容量为\sum{A_i}/2的0/1背包, \sum{A_i}/2 - 2 * f[\sum{A_i}/2]即为答案.
*gXX给出了利用一次函数的证明方法, (待补)
*对于此类数据类型误导题目, 可以通过数学推导, 或者编程实验证明.
[标程做法] by ftiasch
(1) 讨论极值位置
固定x_1, x_2, ..., x_{n - 1} .
f(x_n) = (x_1 + x_2 + ... + x_{n - 1}) * x_n + () ...
这是个关于x_n的一次函数, 所以只有在端点处才会有极值.
x_1 * x_2 + (x_1 + x_2) * x_3 + (x_1 + x_2 + x_3) * x_4 + ...
(2) DP
dp[i][j]表示前i个数, 在x_1 + x_2 + ... + x_i = j的情况下的答案, 转移就是枚举现在是弄个+a_i还是-a_i。
NOIp06真题, 3h, 120 >_<
P1: 环状区间DP, 10
(1) 方程
f[i][j]表示合并第i颗珠子的头标记到第j颗珠子的尾标记的最大值
f[i][j] = max(f[i][k] + f[k][j] + A[i]*A[k]*A[j]) (i <= k <= j)
(2) 实现
改写方程
f[l][i]表示从i开始, 合并l颗珠子(指头标记)的最大值
f[l][i] = max(f[k][i] + f[l-k][i+k] + A[i]*A[i+k]*A[i+l]) (1 < k < l)
*注意下标; i的枚举范围是[1, 2n-1], 环状; -> 当成链做只有50
*和一般的区间模型最大的不同, 在于头尾标记, 事实上比较可行的方法是在草稿上按照要求画出珠子, 以检验下标;
P2: 简化版孩子背包 -> 分组背包, AC
*Nettle的某道模拟题和此题的命题思路如出一辙, 都有两种做法, 一种是直接套用更复杂的模型, 另一种是改变现有模型. 要充分挖掘问题性质.
P3: 模拟, 10
(1) 找空挡
从time[opt[k]][count[opt[k]]]开始
验证区间长度
++Time //这里类似字符串匹配
(2) 在空挡标记时间
(3) 更新完成时间, finish[opt[k]][count[opt[k]]] = Time + time[opt[k]][count[opt[k]]] - 1;
(4) 更新最后完成时间
*一定要在草稿纸上写出流程和关键语句
P4: 递推, 没时间, 6h
题目中第二次描述给了很关键的暗示(看了BYVoid的题解豁然开朗, 捶胸顿足中):
[状态] f[i][j]表示i为2^k进制数最高位为j
[方程] f[i][j] = \sum{f[i-1][m]} (j+1 <= m < 2^k)
ans = \sum{f(m, 0)} (3 <= m <= w/k + 1) + \sum{f(w/k + 1, i)} (1 <= i < 2^(w%k)-1)
*可以直接利用记忆化, calc[][]标记是否计算, int70, 高精90
*由于题目的范围很大, 考虑滚动数组(注意每次计算初始化), 递推计算f[][], 累加同时进位, 高精度压位, 大概第10个点1.35s. 去掉了运算符重载, 第10个点0.9s.
*这题属于典型卡常数, 赛场上, 能观察出方程并调出70分即可, 时间充裕可以考虑调试90分.
*注意运算符优先级(10)
*高精度调试技巧
(1) 初始化(初始化位置)
(2) 进位(模拟手算)
(3) const(防止修改不应修改的值)
rqnoj 341[SPFA], 40min
(1) 无向图看成有向图
(2) 漏打循环队列
(3) first[]初始化错位
*草稿纸很重要!!!
11.6
叉姐模拟赛, 210/300
P1: 2个trick, long long, 还有范围
P2: 0/1背包变形
预处理, 以c[i] - v[i]为关键字升序排序
P3: 二分图判定
*无向图, 考虑两条边
*描述歧义, 特判没写, 不说了, 浪费了2h
NOI 2001 食物链[并查集], WA
和之前的做法完全不同, 题目是环状依赖.
*尼玛今天写check.bat都不check..
[题解]http://winterlegend.blog.hexun.com/25409221_d.html
NOIp04 合并果子[小根堆, STL实现]
学习STL中的优先队列:
[声明] priority_queue<int, vector<int>, greater<int> > q;
*小根堆, greater; 大根堆, less;
[弹出队首] q.top(); q.pop();
[加入元素] q.push(k);
ftiasch, 2010114模拟赛
P1: NOIp10第三题, 判定二分图
P2: 找个兔子, 在不超过L的范围断开, 直接验证
P3: 把每个时刻的萝卜加入堆(当前时刻没有, 则添加下一时刻), 维护当前时刻最大值, 累加即可.
P4: 最小生成树 + 背包
对于一条路(i, j), 需要消耗D(i, j)个同类型的萝卜, 因而需要一次0/1背包.
NOIp04 合并果子[小根堆, 手写heap]
堆只维护队首元素最小值, 不对队中其他元素负责.
up() 直接上翻
down() 尽量取2*k+1(目的就是找到最小值), 然后下翻
11.7
Contest MAR11 packdel[dij+heap], 1h
(1) dij+heap元素出队时, 标记已计算(done[k])
(2) 手写可以用cmp函数比较, 注意A[k]与k的区别
叉姐模拟赛,
*手工修正了50%的数据..什么状况
NOIp10, 引水入城[BFS+贪心+分析]
*认真读题, 题目仅考虑最下面一行是否有水, 卡了40min
(1)无解, 30
对第一行进行floodfill即可, 可以BFS实现
(2)有解, M <= 10, 50, 25min
二进制生成子集, 然后利用floodfill填充, 并判定是否满足题意, 维护最小值即可
(3)有解, AC, 2.5h
[重要结论]有解当且仅当, 第一行某个城市流经最后一行城市的结果连续.(若不连续, 必然不满足题意)
因而可以将题目转化为最少线段覆盖问题.
利用邻接表维护当前点的线段(注意退化为点的情况), 贪心过程如下:
1) 从L = 1开始, 对于(L, R), 维护最大的R_Max
2) 更新L = R, R = R_Max+1(左闭右开区间)
3) 重复以上步骤, 直到R > M
*贪心问题, 以及和区间有关的问题不熟悉, 待阅<浅谈信息学中的区间问题>
*要在纸上写出关键条件和大致算法流程以及语句, 不要把时间浪费在调试上
待阅<浅谈信息学中的区间问题>
*阅毕, 涉及到了白书上三类区间问题
11.8
Tyvj1038[RMQ -> ST], 1.5h
ST算法(RMQ问题, 离线算法, O(NlogN)建表, O(1)查询)
[状态] f[i][j]表示从[i, i + 2^j - 1]的最值
[方程] f[i][j] = max{f[i][j-1], f[i + 2^(j-1)][j-1]} (以j为阶段; 1+(1<<j)<=N, 保证实际意义合法)
[查询] 对于区间[i, j], 令k = [log2(j-i+1)], 答案即为max{f[i][k], f[j - (1<<k) + 1][k]}
*不要相信样例的调试性, 写make, 或者打小数据手算
Tyvj1297[ST], 40min
*log_2打错, 不妨自己写函数
Tyvj国庆新赛制模拟赛, Day2P2, game[单调栈+ST], 1.5h
(1) 单调栈, 维护L[i], 表示A[L[i]..i-1] <= A[i]
while(A[L[i] - 1] < A[i])
L[i] = L[L[i] - 1];
(2)ST
*检查方程和查询的写法, 静态调试, 别盲目做
*认真读题
NOIp08, message[双进程DP],50min
[状态]f[k][i][j]表示从(1,1), 两人分别走到(i, k-i), (j, k-j)的最大值
[方程]f[k][i][j] = max{f[k-1][i][j], f[k-1][i-1][j], f[k-1][i][j-1], f[k-1][i-1][j-1]} + A[i][k-i] + A[j][k-j] (i != j)
[答案]max{f[M+N][M-1][M], f[M+N][M][M-1]}
*注意状态的实际意义
*注意不要随便用简化写法, 事实上简化写法是最可能出问题的地方
Tyvj国庆新赛制模拟赛, Day1P3, maze1[双进程DP], 1h
*注意读题, 每个格子可能有不只一个面包圈
方程和上一题一样, 说一下如何记录方案:
利用数组t1[k][i][j], t2[k][i][j]分别表示两个人走的途中可以吃到的最多的面包圈, 答案在其中取最大值即可. 标程把对每个格子面包圈的个数的计算加入了方程中, 从而避免了讨论.
*这两天做陈题发现问题, 由于对于题目残存的印象导致的读题问题非常多.
Tyvj国庆新赛制模拟赛, Day2P1, ship[计算几何], 15min
典型的卡读题的题目, 稳定的定义是, 正多边形的几何重心落在最高的柱子们构成的多边形中(不能在边界).
直接检查下标即可, 连续两最高柱子的下标只差小于(N+1)/2
Tyvj国庆新赛制模拟赛,Day2P3, maze2[二分+BFS]
*学习了白书上的二分查找上下界的方法, 并注意到是左闭右开区间.
-> 按照当时帖子的说法, 标程错误, 修正一处后仍然WA.
11.9
叉姐模拟赛Stage4, 50 + 40 + 0 >_<
P1: 高精度
裸的高精度. 自己写个30%算法跑一下可以发现, f[A][B] = A*B-1(好吧那个奇葩的递推式怎么YY出来的)
*三处写挂: (1)数组范围 (2)len的计算(乘法和加法不同, 要命的是还手工屏蔽了小数据) (3)进位(其实不需要特判)
*一句话总结高精度写法
[加法]更新位值, 累加, 进位, 退位
[乘法]更新位值(不同), 累乘, 进位, 退位
*注意的情况, 进位(比如10)
[背景]其实是有块a * b的巧克力, 你要把他掰成1 * 1的巧克力, 求要掰多少次
P2: 枚举
[关键结论]值最小的聚集点一定在某个点的x上, 某个点的y上(可以考虑证明一维的情况, 然后推广)
*昨晚的讨论不充分, 错误的认为值最小的聚集点一定和某个点重合, 且任意多点在某点聚集等价(事实上仅在两点的时候成立, 今天发现30%程序是错的)
然后枚举每个x,y, 计算每个点和他们的曼哈顿距离, 排序后累加前k个, 维护最小值.
复杂度大概是O(N^2 * NlogN)
*改写程序务必注意循环变量是否打错
P3: DP
*现场的时候NC了, 写了一个DFS, 大概能处理N <= 8的情况
(1) 50%做法
[状态]f[i][j][k]表示取到A[i], B[j], C[k]的最小值
[方程]f[i][j][k] = min{f[i-1][j][k] + A[i]*p, f[i][j-1][k] + B[j]*p, f[i][j][k-1] + C[k]*p} (p = i+j+k)
[初始化]f[0][0][0] = 0;
(2) 100%做法
[状态]f[i][j]表示取到A[i], B[j]的最小值
[方程]f[i][j] = min{f[i-1][j] + A[i]*p, f[i][j-1] + B[j]*p} (p = i+j)
[初始化]f[0][0] = 0;
[记录方案]按照f[i][j] == f[i-1][j] + A[i]*p倒推, 循环即可, 注意边界.
*直接记录t[i][j] = i的话, 需要注意i==j的情况, 这里应该按照方程的实际转移处理, 而这样的情况很多, 所以没必要使用;
*先对序列A,B进行一次DP, 得到A和B合并后的序列D, 然后对C,D进行DP, 即可得到结果
*想不出来的题目可以敲暴力观察, 或者画画图; 暴力程序一定要写, 一方面启发思路, 另一方面验证正确性.
叉姐模拟赛Stage3, 20 + 60 + 0 >_<
*从哪里跌倒要从哪里爬起来...
P1: 模拟, 求外表面积(不考虑内部表面积)
[1] 对每个立方体的边界染色, 然后从六个面逼近
*对于有洞的情况会挂, gXX表示不会, 原因不知.
[2] 正确做法
(1) 对每个立方体的边界染色, 维护最大坐标
(2) 从(0, 0, 0)开始BFS,
i, 已染色的点不标记已读(遇到的Cnt++, 但不入队)
ii, 未染色的点标记已读
*标程范围开小, 已经更新数据
P2: 枚举
考虑仅有三个数的情况:
操作前a, b, c 差分为(b-a, c-b)
操作后a, a+c-b, c差分为(c-b, b-a)
可以发现操作的实质就是交换差分.
不妨设d[i] = A[i+1] - A[i],
那么A[i] = A[1] + \sum{A[j]}(1 <= j < i)
即\sum{A[i]} = N*A[1] + \sum{d[i] * (N-i)}(1 <= i < N)
*注意范围会爆int, 要用long long; 注意下标;
P3: 查找中位数[数据已修正]
(1)60%做法
对每个区间复制一次, 然后qsort
(2)AC做法 by gXX, 实现无能
大意就是想把所有区间的中位数搞出来。其实可以用堆吧?
就是枚举一个左端点, 一个一个往里面加, 然后用两个堆来维护中位数。就是一个最大堆一个最小堆, 然后不断丢来丢去的过程。
呃。大概就是相当于要维护第k大这样的吧。开一个最小堆, 里面只有k个元素, 而且是最大的k个, 然后其他的丢到最大堆里面。
然后当你k要增大的时候,就把最大堆的堆顶拿过来。要减小的话, 就把最小堆的堆顶丢过去。
就是这个意思, 此消彼长, 道法自然。
11.10
NOIp09 靶形数独[DFS+剪枝]
*手工指定搜索顺序, 1.5h调试无能
*题目中不考虑对角线, 手工顺序无效!!!
利用frist[][], second[][], grid[][]分别表示每个行/列/小九宫格的填数情况, countX[], countY[]统计一开始行列的填充情况.
(1) BFS生成score[][]
(2) 读入数独, 统计countX[], conutY[], 记录填充情况
(3) 对countX[], countY[]进行降序间接排序
(4) DFS, 状态DFS(x, y, sum)
1) x == N+1, 统计答案
2) y == N+1, 换行
3) (x, y)已填充, 更新sum
4) 枚举A[mapX[x]][mapY[y]], 所有涉及值的地方按照map_[]顺序
*[动机]不必要的枚举量, 优化搜索顺序
*90%的测试点在1s内, 1h内可以调试完
NOIp04 虫食算[DFS+剪枝], N h
*注意读题, 是N进制加法, 每个字母代表的数字不同
(1) 70分做法
DFS枚举序列1..N代表的数字, 利用used[]判断当前数字是否使用过
[剪枝]对于竖式上同一列的三个数a,b,c, 显然满足c - (a+b) < 2
*注意各种回溯细节
(2) 80分做法
对每一位进行枚举, 判重和可行性剪枝
*回溯只需一解的情况下, 要注意恢复修改值的时间
*进位要用delta记录, 可能出现多次进位的情况
*else和if的匹配错误, 注意花括号!!!!!!!!
*70分做法的剪枝用了没效果, 网上还有一个剪枝, 同一列三数知二的情况下, 看剩下那个数的两种情况能否使用, 可能可以AC
东方幻想乡Stage1P4[强连通分量, kosaraju实现], 40min
(1) 正向对每个点进行DFS, 搜索完该点后加盖时间戳
(2) 边反向, 按照时间戳逆序DFS, 标记根节点
*NOIp09第三题用了类似的边反向的做法
WZOIStage2 P2[SPFA], 20min
范围很大, 题解给出的AC做法是DAG的DP,事实上SPFA可以AC.
11.12
敲Day1P2三种版本, 实测ST+邻接表, N <= 30000; 裸的做法, N <= 15000