1.组合数学
排列组合
P5520 插空法——不相邻问题时的做法
P3323 分类讨论,考虑排男生、老师、女生的顺序,注意老师两个中间也可以插,分成老师本就不相邻和老师原本相邻,插进女生不相邻两种,高精度计算即可
容斥原理
P3197 问n个牢房,m个宗教,每个相邻房间若宗教相同则粤越狱。考虑两两不相邻,第一个有n种选择,后面的都有(n-1)种选择,n*(n(m-1)-(n-1)(m-1))快速幂求解即可
2.STL栈
rc-国赛-03删除屏蔽词
发现特殊之处在于屏蔽词两个字符,类比括号序列,()就消掉否则就不消,最后逆序输出栈即可。这种题一定要注意特殊条件,如天梯赛有一道不是字符串题,26个代号提示你将数字化为字母进而转化为字符串解题。
4.数论解题
很重要一点就是列算式,找特殊
P1445 很容易知道x,y>n! 但是,列出y=n!+k (k为正整数)消元不容易。继而找到x=(n!)^2/k+n! 然后发现就是求k的个数,应用约数个数定理即可
5.树
重要知识点:树上两点最近距离=Ro->a+Ro->b-R_o->lca(a,b)
求最近公共祖先应用dfs序码量最小,时常记
void dfs(int r, int f)
{
for (int i = 1; i <= 20; i++)
{
if (i == c[r])
{
dp[r][i] = dp[f][i] + 1;
}
else
dp[r][i] = dp[f][i];
}
st[dfn[r] = ++idx][0] = f;
vis[r] = 1;
for (int i = 0; i < edge[r].size(); i++)
{
int to = edge[r][i];
if (!vis[to])
{
dfs(to, r);
}
}
}
int cal(int x, int y)
{
return dfn[x] < dfn[y] ? x : y;
}
int lca(int x, int y)
{
if (x == y)
return x;
else
{
if ((x = dfn[x])> (y = dfn[y]))
swap(x, y);
int t = log2(abs(x - y));
return cal(st[x + 1][t], st[y - (1 << t) + 1][t]);
}
}
`
//省略了st表建立部分,注意用cal代替min计算
差分
当出现段计数,常常要用到差分。比如天梯赛里面的胖达山头。就是用差分,选择重叠数最多的时间段;CF2014D,问一个d区间有多少种不同的线段(部分),稍微变一下,把左右界改到(max(0,l-d+1),min(n,r+d-1))即可
数位dp
求一段大区间的和也可以用数位dp,对计数值乘以数值即可,但是要注意常数问题,CF2132D,比赛时把【0,maxnum】拆成两个区间,因为常数问题就超时了。