Contest #1 CQ Round 1 (巴蜀命题) 2016/10/25
Rank: 19 Score : 140
从现在开始每场训练赛尽量写一点总结吧,开始的有点晚,但是还有十几场吧。
这场比赛题目难度一般,比较分散。
暂时不讨论因为没有学2—set而爆〇的T2,本次的T1还是有亮点的:
60分没拿到的可以回家种田了。
正解的搜索感觉技巧性很强,但还是有大神想到。
一上来就觉得本题可以分段打表,事实上的确如此。可惜暴力功底不够,花了70分钟左右只搞出两个概率较高的答案,居然两个答案都中,运气爆炸。看唯一AC的大神代码,也不过多打了一点表。暴力功夫有待提高啊。
代码里面有一个细节问题:
const int maxn=100000+5;
int cnt[maxn];
for(int i=1;i<maxn;i++)cnt[i]=1;
申明数组的时候是cnt[maxn],实际上cnt[maxn]指向一个随机的位置,恰好这样就会WA掉第一组小数据(出题人真不错,这都能坑)。所以以后maxn做循环控制变量一定不能取等。
T3上来10分钟直接打完了暴力,但是LCA有点小错,浪费了30分钟以上,最后分析了一半。。。亏的一匹。
Contest #2 CQ Round 2 (一中命题) 2016/10/26
Rank: 4 Score : 294
唯一没AC的居然是第一题?!(LZ的诅咒)
没必要的上限就不要乱搞了,否则WA爆。
这次的T2是原题,T3一般,总之比上次水多了。
Conteset # 3 CQ Round 3 (南开)
Rank: ??? Score: 195
第一题杨辉三角找规律,找的很快,但是写了很久。递推除法在模余系下要用逆元,居然对拍了40分钟才看出来。最后还因为数组爆炸丢了5分。只要不超过限制,数组一定开够啊!
第二题 Trie +DP ,20分钟秒杀,然而只有50分(一行代码啊啊啊,亏的一匹)。写完代码后一定要读一遍再去测样例,否则过了样例容易掉以轻心,没过影响心情。
第三题 50骗分程序达到了预期,正解确实不好想到。
Conteset# 4 CQ Round 4 (八中)
Rank: 12 Score: 180
第一题虽然找到了规律,还是超鬼了。以后这种题暴力写得快一定要打出表来,便于观察。80分是因为超出了unsigned long long ,还有一个简单的特判。以后这种找规律的数学题要注意以下几点:
1>注意数据范围,有些细节用不同的写法可能就不会超long long
举个栗子:
// 求不超过n的 m 的 幂
// Code #1
unsigned long long M=1;
while(M<=n)M*=m;
M/=m;
// Code #2
unsigned long long M=1;
while(n/M>=m)M*=m;
// Code #3
unsigned long long M=1;
M=floor(log(n)/log(m));
M=Pow(m,M); //快速幂
/*
容易发现Code #1 多乘了一次,所以用可能会爆炸。
Code #2 和 Code #3都不会爆炸, Code #3还可以用快速幂。
*/
2> 注意是否有特判,这很容易忽略,对拍的时候 特殊数据和 极限数据 都要注意到。
3> 答案是否需要模,如果有,注意使用乘法逆元
第二题挺水的,秒杀,不多说。
第三题离散化+堆+贪心。
这类题真的不好想,可以从以下几个方面入手:
(1) 局部最优+适当改悔==全局最优
(2) 按顺序讨论某些变量,可能会带来更多的贪心结论。
(3) 合理利用堆和其他数据结构的性质
Conteset #5 XSFZ VS NK Round 6
Rank: 8
活活把Rank 1丢啦!亏得一匹。
第一题:简单的搜索,不说了。
第二题: 问题转化后:区间DP。
接下来问题来了,一个小地方没有写Sort,30分没有了.
以后最后的几分钟一定要读一读自己的代码!!!
第三题:
Contest #6 CQ Round 5(巴蜀)
Rank: 18 Score: 100
第一题这一次还算正常,一个小时A掉,代码想的有点久,水题。
第二题树形DP,想到了,但是状态没有定对,爆搜30分没有拿到应该好好反省,这种题写搜索一定保证在半个小时以内写完写对,小分到手。 暴力功夫不够?
第三题 本来完全想对了90分算法,可是由于两个小错误,WA成0分!细节决定成败啊!
错误1:本来是想图方便,炫炫技,结果反被数据秀了一波。
将两个0到N的数压成一个数的写法 应该是 a*(N+1)+b。注意一定是(N+1)!!
错误2:LCA经典错误(错了几次,没引起重视,终于炸了)
//正确的LCA
int LCA(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
int i,p=dep[x]-dep[y];
for(i=0;i<=S;i++)
if((p>>i)&1)x=fa[x][i];
if(x==y) return x;
/*
注意,这里的k一定不能用倍增上限S代替,否则会导致fa[x][i]在i>k时指向无意义的节点,导致wa
其他地方都可以用S
*/
int k=ceil(log(dep[x])/log(2));
for(i=k;i>=0;i--)
if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
Contest #7 CQ Round 6(一中)
Rank:10 Score: 190
第一题贪心,数据很水,比较暴力的方法也能过,但是贪心原则想了一个小时左右,耗是太久,导致最后一题的搜索都没写完。
第二题: 最短路重新建图+DP
本场比赛的送分题,90分是数据的问题,超过范围了。数组在不超过限制的情况下尽量开大。下面以256MB的内存限制为例,列举一些极限(实际占用大概220MB):
256MB= 58000000个int =29000000个LONG LONG=23200000000个bool
第三题:暴力的搜索裸题
剪枝都想到了,时间不够了,代码没写出来,想到了好的剪枝,不要怕代码难写,能得分就行。
互测赛改悔:
多组数据不要乱用return 0...算出一个答案就愉快的return 0了,于是WA了90分
Contest #8 2015 CQ Round ?
Rank:? Score: 150
第一题 暴力,不说了。
第二题Hash,玄学算法,注意两点:
(1)一个哈希冲突可能性有点大,不妨用两个。
(2)连续子串的Hash不用重复计算,是可以O(1)转移的。
(3)计算Hash值的时候不要乱取模(这个很容易错)。
第三题
爆搜拿到了暴力分,其实正解是动规。
第一反应认为有后效性,其实化简之后是没有后效性的,坑啊!
形如F[n]的函数,如果只是和N有关的多项式,可以和数列一样退下标得到递推式。
Contest #9 2016 CQ Round 7 (By nodgd)
Rank & Score: 不可描述
被Nodgd支配的恐惧!!
第一题: 组合数学
在第一个简单问题上时间花的太多,凡是关于组合数学的题,先在草稿本上把杨辉三角画出来肯定是没错的,非常有利于快速找到规律。还有要对一些组合数学的模型熟悉比如这次涉及到一个隔板原理:
将n个小球分成m组的方案数为C(n-1,m-1)。
证明:考虑将n个球排成一排,在n-1个空隙中插入m-1个隔板,即分成了m组,故方案数为C(n-1,m-1)。
题目链接 :A
第二题: 线段树+变态Lazy标记
这道题确实非常巧妙,主要体现的是对线段树Lazy标记非常深刻到位的理解。
lazy标记是用来干什么的? 传递修改操作 ,通过标记区间来降低修改的时间复杂度
首先看到这个题想到了一个经典的题:
维护一个序列,支持以下三种操作:
①Add(L,R,V) 将 [L,R]这段区间的值增加V
②Set(L,R,V) 将 [L,R] 这段区间的值设置成V
③Query(L,R) 查询L,R区间的最大值
这道题的实现用了两个Lazy标记,pushdown(传递标记)的时候采用的是先考虑Set,再考虑Add,
update的时候 对于set先清除Add标记,对于Add则不用清除set标记。
为什么这个题不能照搬,用两个Lazy呢?
上题中,Set和Add两个标记虽然看起来是独立的,但我们注意的那些(比如先考虑Set,再考虑Add),其实就是找到了两种操作的一种联系,体现到了标记的处理上,实际上这两个标记是一个整体,并不互相独立。而处理标记的关键在于如何叠加标记:
比如add标记的叠加非常简单,直接加上一个值就行。这个题同样,要找到两种操作之间的联系,通过数学上的划归,最后发现必须使用三元组(a,b,c)标记才能转移下去。
所以不管多少个标记,他们都该是统一的,可以转移的,总之Lazy的核心就是 转移。
Contest #10 2016CQ Round 8 (by 八中)
Rank: 12 Score: 200
这场为什么我骗分这么厉害?
第一题: 一下想到了贪心,写了一下,过了样例,手出了几组错数据居然也过了,于是开开心心的交了,还好这题贪心比较厉害,可以骗80分。
正解 DP,为什么当时没想一想? 至少应该写一下状态吧,这题很容易看出来。
第二题: 单调队列 确实没看出来,写了个二维的RMQ,其实这题一维RMQ每行开一个就行了,感觉以后有点用,贴在这里。
拿到一个无法入手的问题怎么办? 从简单的情况入手!
如果是一维的,怎么做? 对于x找出左边能延伸到的L[x],右边能延伸到的R[x]-----广告牌模型!
所以枚举第i行到第j行,求出min[k] (第i行到第j行第k列的最小值),把二维的矩阵变成一维的,再用一个单调队列就行了。
二维RMQ代码:
const int maxn=300+5,inf=0x3f3f3f3f;
int n,m,s[maxn][maxn],f[maxn][10][maxn][10];
int RMQ(int x1,int y1,int x2,int y2){
int k=0,t=0;
while((1<<(k+1))<=x2-x1+1)k++;
while((1<<(t+1))<=y2-y1+1)t++;
int Min=f[x1][k][y1][t];
Min=min(Min,f[x1][k][y2-(1<<t)+1][t]);
Min=min(Min,f[x2-(1<<k)+1][k][y1][t]);
Min=min(Min,f[x2-(1<<k)+1][k][y2-(1<<t)+1][t]);
return Min;
}
int main(){
int i,j,k,p;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)scanf("%d",&s[i][j]);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)f[i][0][j][0]=s[i][j];
for(i=1;i<=n;i++)
for(j=1;(1<<j)<=m+1;j++)
for(k=1;k+(1<<j)-1<=m;k++)
f[i][0][k][j]=min(f[i][0][k][j-1],f[i][0][k+(1<<(j-1))][j-1]);
for(i=1;i<=m;i++)
for(j=1;(1<<j)<=n+1;j++)
for(k=1;k+(1<<j)-1<=n;k++)
f[k][j][i][0]=min(f[k][j-1][i][0],f[k+(1<<(j-1))][j-1][i][0]);
for(k=1;(1<<k)<=n+1;k++)
for(p=1;(1<<p)<=m+1;p++)
for(i=1;i+(1<<k)-1<=n;i++)
for(j=1;j+(1<<p)-1<=m;j++){
int& x=f[i][k][j][p];
x=f[i][k-1][j][p-1];
x=min(x,f[i][k-1][j+(1<<(p-1))][p-1]);
x=min(x,f[i+(1<<(k-1))][k-1][j][p-1]);
x=min(x,f[i+(1<<(k-1))][k-1][j+(1<<(p-1))][p-1]);
}
return 0;
}
第三题 是辗转相除法的运用,就是眼瞎,永远看不出来,但是由于题目本身导致答案简单,骗分骗了90分,还行吧。
小小的改悔: 使用unique之前先排序!!!!!!