GGN_2015退役后打算重新认真学习OI ,并在此记录一些学习中的心得体会。由于此部分内容主要为算法实现过程中出现的各种错误,以此丢人现眼。(温馨提示,此网页手机端体验局差,强烈建议在电脑端查看。)
退役后做题总览
调试到快死才调出来的,加粗了,一遍就水过的题画了删除线。(我就一粗人。。)下述题目均可在洛谷/vjudge/BZOJ上找到,如遇BZOJ权限题,会特殊标明,正在逐步完善题目链接。
动态规划系列
图论相关
算法 | 题目 |
---|---|
差分约束 | 「洛谷P1250」 「洛谷P1993」小K的农场 「洛谷P2294」 「洛谷P3275」 [SCOI2011]糖果 「洛谷P5960」 「洛谷P2474」 [SCOI2008]天平 |
数据结构
算法 | 题目 |
---|---|
主席树 | 洛谷P3834 【模板】可持久化线段树 2(主席树) 洛谷P1383 高级打字机 |
树套树 | 洛谷P3157 [CQOI2011]动态逆序对 |
一些巧妙的思路整理
此栏目暂无。
每日刷题/总结记录
2020-07-20
题号 | 题目名称 |
---|---|
洛谷P2657 | [SCOI2009] windy 数 |
- python 写OI题一定要记得
global
- 注意枚举下一位的所有可能取值时,值域不要用错位。
elif op == 1:
tmp = 0
for j in range(0, self.A[x-1]): # !!! we should fill x-1 not x here !!!
if(abs(j-v)>=2):
tmp += self.f(x-1, 0, j)
if(abs(self.A[x-1]-v)>=2): # !!! we should fill x-1 not x here !!!
tmp += self.f(x-1, 1, self.A[x-1]) # same as upon
self.dp[(x, op, v)] = tmp
- 由于最高位上的值一定不是零,所以这种写法是可以的
def solve(self, x):
if(x == 0):
return 1
self.load(x)
tmp = 0
tmp += self.f(self.cnt, 2, 0) #here
for i in range(1, self.A[self.cnt]):
tmp += self.f(self.cnt, 0, i)
tmp += self.f(self.cnt, 1, self.A[self.cnt]) # and here
return tmp
写程序的时候,误以为,这是bug。
4. python类一定要记得self.
题号 | 题目名称 |
---|---|
洛谷P1962 | 斐波那契数列 |
c++
里不要定义一个叫matrix
的结构体,叫mat
得了…- 函数不写
return
各种导致神奇爆炸
mat uno(int n) {
mat ans = {n, n};
for(int i = 1; i <= n; i ++) {
ans.a[i][i] = 1;
}
return ans; // 我最开始的时候没写return
}
- 常规错法,记得开
long long
题号 | 题目名称 |
---|---|
洛谷P2602 | [ZJOI2010]数字计数 |
疯狂调试一下午,最后终于在晚上九点调出来了。(洛谷题解里好像很少有跟我同一写法的。)
- 最开始的时候,这个地方忘了开
long long
,但是我最后是define int long long
过的,那就无所谓了。
void load(long long x) {
/// load x into A[], forget to long long at first
cnt = 0;
while(x > 0) {
A[++ cnt] = x%10;
x /= 10;
}
memset(vis, 0x00, sizeof(vis));
}
vis[x][op][v] = 1
,记忆化除非超出定义域,否则不要直接返回一个值,而是要现给dp
数组赋值,最后再返回dp
数组中的值。下一次很可能返回未初始化的dp
数组中的值。
long long f(int x, int op, int v) {
if(vis[x][op][v])
return dp[x][op][v];
vis[x][op][v] = 1; /// may be i'm always for getting this
if(x <= 1) { /// allow for x = 0 (cnt = 0)
dp[x][op][v] = 1; /// don't write return 1 here !!! or you will WA
}else{
...
- 推一个前缀的值,放错位置,填错值。
for(int j = cnt-1; j >= 1; j --) {
pre = pre*10 + A[j+1];
/// this should be set at the first line not the last line of the loop, j+1 not j
...
2020-07-21 在学校机房
题号 | 题目名称 |
---|---|
洛谷P3413 | SAC#1 - 萌数 |
此题思路真心巧妙,基于连续三位的回文串判定具有充要性,但是我今天早上才调出来。
- A[1] 误写为A[i]
for(int i = 0; i <= A[1]; i ++) {
tmp += f(1, i==0?2:(i==A[1]?1:0), 10, i); /// A[1] not A[i] !!!!
//printf("[debug] i = %d, contribute to tmp = %lld\n", i, f(1, i==0?2:(i==A[1]?1:0), 10, i));
tmp %= p;
}
- 调试结束后,忘记把输出改回正常
printf("%lld", ((solve(R, cntR)-solve(L, cntL)+judge(L, cntL))%p+p)%p);
//printf("%lld\n", solve(R, cntR)); /// forget to transport the output to normal
题号 | 题目名称 |
---|---|
HDU 2089 | 不要62 |
一遍过,开心d。
题号 | 题目名称 |
---|---|
LibreOJ 10166 | 数字游戏 |
带模运算记录余数的数位dp,一定要注意不要顺手就写dp[1]=1,因为有可能最后一位与所要求的余数不符合。另外题中说有多组数据,没看到。
if(x == 1) {
dp[x][v][op][md] = v%N == md; /// not 1
}else {
...
while(scanf("%d%d%d", &a, &b, &N) && a && b && N) {
printf("%d\n", solve(b)-solve(a-1));
//printf("%d\n", solve(b));
a = b = N = 0;
}
2020-07-22 python日
这一天我一直在调试我之前用python
写的迷你网络通讯工具ggntalk
。c语言选手转python非常容易写错print
和printf
,然后我要教育自己不要乱写try
不然忽略了解释器的报错很难调试。
「HDU4507」恨7不成妻暂时弃疗,昨天我调了一宿结果还是TLE,我估计我的算法没救了,改天照着题解重写吧。
2020-07-23 返校领毕业证
合影留念,下午在学校和学弟学习差分约束系统,并给学弟普及了johnson
算法。
题号 | 题目名称 |
---|---|
洛谷P1993 | 小K的农场 |
两个易错点:最短路dis值要初始化,边要开三倍空间(我就没开然后WA/RE彩色一片)。
题号 | 题目名称 |
---|---|
洛谷P1250 | 种树 |
一遍过,开心。注意,差分约束的约束条件一定要找全,要确定使用最短路还是最长路。
2020-07-27 填报志愿费时费力
补写最近的几篇错题。
题号 | 题目名称 |
---|---|
洛谷P2294 | [HNOI2005]狡猾的商人 |
一遍水过,没啥细节。
题号 | 题目名称 |
---|---|
洛谷P3275 | [SCOI2011]糖果 |
首先要开三倍内存,不然会RE/WA。
其次,题中说每个小朋友都能分到糖,因此不能让小朋友分到的糖的数量是0。我才用的做法是建立一个超级源点,令超级源点的dis值为1,但是因为我比较zz,所以我最后统计答案是误把超级源点的dis值也统计到了答案中,因此输出比标准输出大1。
最后,spfa需要slf优化才能通过此题。(LLL是怎么优化来着??想不起来了。)
题号 | 题目名称 |
---|---|
洛谷P3275 | [SCOI2011]糖果 |
水题一遍过。
题号 | 题目名称 |
---|---|
洛谷P2474 | [SCOI2008]天平 |
多元最短路差分约束系统用来计算两个变量差的最大值和最小值。
- 弗洛伊德该continue就continue。
if(i == k) continue; /// !!1
for(int j = 1; j <= n; j ++) {
if(i == j || j == k) continue; /// !!
- 不要把i写成j(常规错误)
if(maxd[i][a] > mind[b][j] || maxd[j][a] > mind[b][i]) { / 写成mind[b][j] j should b i
lcnt ++;
//printf("lcnt++ : i = %d, j = %d\n", i, j);
}
- dis[i][i] = 0 不初始化当然是不行的。
2020-07-31 紧张的备课时光
前天简化了ggntalk-pro
,并和重伯君和HJQ大佬完成了通信调试。
昨天晚上写了一个带GUI的ggntalk-pro
,感觉不错,不过重伯君很忙,我请增基大佬做了通信调试。
题号 | 题目名称 |
---|---|
HDU1400 | Mondriaan’s Dream |
!!!i 和 j 写反了三次。。以后一定要注意,推公式时候用的字母,和编程时候用的字母一定要对应,不然很容易写反。
int left = getb(S, j); /// j not i
int up = getb(S, j+1); /// j+1 not i+1
T = setb(T, j, 0); /// setb(T, j, 0) not setb(T, i, 0)
T = setb(T, j+1, 0); /// setb(T, j+1, 0) not setb(T, i+1, 0)
if(i != n) {
f[i][j+1][setb(S, j, 1)] += f[i][j][S]; /// setb(S, j, 1) not setb(S, i, 1)
}
if(j != m) {
f[i][j+1][setb(S, j+1, 1)] += f[i][j][S]; /// setb(S, j+1, 1) not setb(S, i+1, 1)
}
题号 | 题目名称 |
---|---|
HDU1693 | Eat the Trees |
- 位运算忘加括号
int getb(int S, int p) {
return (S&(1<<(p-1)))>>(p-1); /// miao not S&(1<<(p-1))>>(p-1)
}
- 各种智障错误:忘输入n和m,忘了用题中给出的障碍物位置。
题号 | 题目名称 |
---|---|
洛谷P5056 | 【模板】插头dp |
初次提交五彩斑斓,开大数组至14后红绿掺半。
一定要注意右下角的位置要特判,可以闭合回路。但一定要想到,所谓的“右下角的位置”不一定真的是「右下角的位置」,因为图中可能有障碍物,这些障碍物可能会占据最后一排靠右侧的几个位置。但是,无论障碍物如何分布,可以闭合回路的位置只能有一个。
if(i==xm && j==ym) { /// 忘记处理右下角的特殊情况!!!/// 右下角处理得不对!!!不一定真的是右下角
A[j] = A[j+1] = 0;
int T = pack(A, m+1);
if(f[i][j+1].find(T) == f[i][j+1].end())
f[i][j+1][T] = 0;
f[i][j+1][T] += f[i][j][S];
}
2020-08-01 骑电动车上高速
翻vjudge时候翻到了这个:蓝书《算法竞赛入门经典-训练指南》题目一览
和andy大佬讨论了一些关于插头dp的简单问题,安利了一些最短路和线段树方面的模型。
2020-08-03 和YZB大神到三好街买电脑
acer - swift 3 ¥5600,装了个win10/ ubuntu 20.04双系统,到目前为止体验还不错(其实刚才在vim里死机了一次)。
复习了一下主席树的模板(突然发现自己代码能力没有想象中那么垃圾)
昨天完成了自制pastebin,但是就是传送文件的大小不能超过400Byte(顶个卵用。。。)
题号 | 题目名称 |
---|---|
洛谷P3834 | 【模板】可持久化线段树 2(主席树) |
首先,不离散化真的会MLE。尽管动态开点,还是会MLE,没有什么商量的余地。
其次,注意一些智障的细节。(离散化时A[i]误写成A[x],kth 中rch[rr]误写成lch[rr]。)
用线段树套线段树写了一下洛谷P3157 然后TLE了两个点,感觉没救了,可能常数过大吧。(2020-08-04, HJQ大佬加了个树状数组就A了此题,OTL。)
2020-08-04 备课日
题号 | 题目名称 |
---|---|
洛谷P1383 | 高级打字机 |
最开始的时候误以为此题要做树上主席树,后来发现undo操作也可以被undo,问题似乎比我想象的要简单,这样只要一棵普普通通的主席树就可以了。
void add(int& rt, int l, int r, int p, int v) {
int nn = ++ ncnt;
cpy(rt, nn);
if(l == r) {
val[nn] = v; /// val[nn]=v not val[rt]=v !!!!(rt may = 0)
}else {
int mid = (l + r)/2;
if(p <= mid) {
add(lch[nn], l, mid, p, v);
}else {
add(rch[nn], mid+1, r, p, v);
}
}
rt = nn; /// remember to save
}
注意不要修改结点rt
的信息,而是修改结点nn
的信息,最后将引用rt
指向nn
。
题号 | 题目名称 |
---|---|
洛谷P1972 | [SDOI2009]HH的项链 |
一遍过,不过这道题的思路很不错,说实话不是我自己想出来的。倘若询问的右端点恰好是序列末端,统计不同元素的种类数,可以先找到每一种元素出现的最右位置,生成一个新数列B如果A[i]=x是元素x最后一次出现,则记B[i]=1,否则记B[i]=0,统计[L, N]的区间和即可得到该区间元素总数。
考虑到可以离线,对所有询问以询问区间有端点的下表按照从小到大排序,并按照排序顺序一次回答这些询问。将A中位置依次考虑,并不断调整B数组的内容,用树状数组维护B的前缀和即可快速应答对于区间和的询问。
题号 | 题目名称 |
---|---|
洛谷P3157 | [CQOI2011]动态逆序对 |
在HJQ大佬的指点下终于A掉了这道题,犯了一些常见的错误,如将i--
误写为i++
。
具体的卡常方法如下:尽量少使用树套树,用树状数组初始化出每个位置i对逆序对数的贡献,然后在树套树上记录被删除的点,用来统计删除过程中每个位置与删除前减少的贡献,这样可以把树套树的调用次数减半。
2020-08-05 ~ 2020-08-07 出题三日
和HJQ大佬在合作下成功完成了一套很水的模拟赛,感谢HJQwQ大佬和linly大佬的鼎力相助。
一天不登陆洛谷就从绿名调回到蓝名了,虽然说我曾经是红名,但是退役后哪有不蓝的。。。
学习了一下如何用marp写ppt,但是不幸的是它的编译功能出了点问题,只能编译成html,编译成pdf貌似需要chrome打印。