「Solution Set」7/3
P4433 [COCI2009-2010#1] ALADIN
我们发现就是区间加一个等差数列,但是要取模后的。
我们考虑加一个首项为 \(A\),公差为 \(B\),项数为 \(n\) 的等差数列,还要对 \(C\) 取模。
那么和就是这样的:\(\sum\limits_{i=0}^{n-1} Bi+A-\lfloor\frac {Bi+A}{C}\rfloor \times C\)
然后前面两项能用通项求,后面能用类欧求和。
然后就是线段树普通操作了!
就是因为空间 64MB 所以需要离散化,然后处理起来挺麻烦的吧((
P6139 【模板】广义后缀自动机(广义 SAM)
我仍然不理解 SAM.jpg
就是在每插入一个串的时候将 lst 置成 \(1\) 就行。
但是需要判一下此时 \(lst\) 有没有向 \(c\) 的出边。如果有的话,那就不应当新建节点,而是直接在原来的基础上做
void add(char c)
{
int p=lst;
if(st[lst].ch.count(c))
{
int q=st[p].ch[c];
if(st[q].len==st[p].len+1) lst=q;
else
{
int clone=++tot; st[clone].len=st[p].len+1; st[clone].fa=st[q].fa;
st[clone].ch=st[q].ch;
while(p!=-1&&st[p].ch[c]==q) st[p].ch[c]=clone,p=st[p].fa;
st[q].fa=clone; lst=clone;
}
return;
}
int cur=++tot; st[cur].len=st[lst].len+1;
while(p!=-1&&!st[p].ch[c]) st[p].ch[c]=cur,p=st[p].fa;
if(p==-1) st[cur].fa=1;
else
{
int q=st[p].ch[c];
if(st[q].len==st[p].len+1) st[cur].fa=q;
else
{
int clone=++tot; st[clone].len=st[p].len+1; st[clone].fa=st[q].fa;
st[clone].ch=st[q].ch;
while(p!=-1&&st[p].ch[c]==q) st[p].ch[c]=clone,p=st[p].fa;
st[cur].fa=st[q].fa=clone;
}
}
ans+=st[cur].len-st[st[cur].fa].len;
lst=cur;
}
CF204E Little Elephant and Strings
考虑在 SAM 节点上线段树合并,然后求出来每个点是不是出现了 \(k\) 次以上。如果出现了 \(k\) 次以上,那么在这个节点上的答案就是 \(len[p]-len[fa]\),否则就是从parent tree 上最近的节点的串的数量。
我应该还是不理解 SAM 的说。
P4609 [FJOI2016] 建筑师
我们考虑最高的那个一定不会被挡住,所以可以以最高的那个为分界点,之后左右两边分别分成 \(A+B+2\) 组,每组都是最大的能露出来放在第一个,正好相当于圆排列。
所以答案就是
${n\brack {A+B-2}}\times {A+B-2\choose A-1} $
P2664 树上游戏
我们考虑对于每个颜色 \(j\) 求出 \(f_{i,j}\) 表示从 \(i\) 开始走,不经过 \(j\) 号颜色的方案数。答案就是 \(sum_i=\sum n-f_{i,j}\)
然后我们考虑只求 \(g_i=\sum f_{i,j}\)。
我们遍历树的时候,\(p\) 节点的颜色是 \(i\),设从他到子树里别的节点不经过颜色 \(i\) 的节点数是 \(x\),那么这 \(x\) 个节点的 \(f_{v,i}=x\),所以求这个可以在记录每个点最近的子孙颜色相同的,然后树上差分。
[ABC284G] Only Once
你考虑从每个点开始是没有区别的,所以只需要算一个点的答案,然后乘 \(n\) 就行。
然后发现一定是先走一段直线,然后在一个环里循环。
那么可以先选出来会经过的点,然后枚举最先开始循环的位置,然后乱组合数一下
CF1342E Placing Rooks
首先可以知道如果所有都能被攻击到,那么肯定是每行都有或者每列都有。
那么算其中一种情况,乘 2 就行了。
发现 \(k>n\) 是一定无解。
然后发现一定是有 \(n-k\) 列有棋子,所以就是 \({n\choose {n-k}}{n\brace {n-k}} (n-k)!\)