金华3.11
取石子
加强版是CF1033G
首先是不平等博弈,不能算SG值,考虑找规律。
然后可以对A+B取模,因为如果新游戏先手有必胜策略,先手不会去取A+B,后手取了直接模仿,一直按照新策略到后手不得不取A+B。然后按值的大小讨论策略,有点人类智慧。
字符串
容斥最多只能做到((sum |S|)^2),正解可以把反串和正串合成一个AC自动机在上面dp。
网格计数
一条直线的限制:把终点对这条直线翻转一下,那么起点到翻转出来的终点的一条路径唯一对应一条过线的路径,直接减一下
如果有上下两条直线,还是考虑容斥,现在要把路径赋值使得不合法的路径权值是-1,合法的是0。
考虑两个过程:
- 一条路径第一次经过 (y=t) 时 -1,在这之后经过 (y=0) 时 +1,之后重复-1+1
- 第一次经过 (y=0) 时 -1,在这之后经过 (y=t) 时 +1,之后重复-1+1
这样两种加起来的权值符合要求,考虑第一种怎么求:
先减去第一次经过 (y=t) 的,就是一条直线的限制。然后在这些路径中有经过 (y=0) 的要加回来,就再翻转一次,这之后重复直到纵坐标之差大于横坐标之差。
void solve(int a,int b,int c,int d,int yl,int yr){
int xx=abs(c-a),yy=abs(d-b);
int pd=d,ans=C(xx,(xx+yy)/2);
for(int i=1;;i++){
if(i&1){
pd=2*yr-pd;
xx=abs(c-a),yy=abs(pd-b);
if(xx<yy) break;
ans=(ans-C(xx,(xx+yy)/2)+mod)%mod;
}else{
pd=2*yl-pd;
xx=abs(c-a),yy=abs(pd-b);
if(xx<yy) break;
ans=(ans+C(xx,(xx+yy)/2))%mod;
}
}
pd=d;
for(int i=1;;i++){
if(i&1){
pd=2*yl-pd;
xx=abs(c-a),yy=abs(pd-b);
if(xx<yy) break;
ans=(ans-C(xx,(xx+yy)/2)+mod)%mod;
}else{
pd=2*yr-pd;
xx=abs(c-a),yy=abs(pd-b);
if(xx<yy) break;
ans=(ans+C(xx,(xx+yy)/2))%mod;
}
}
printf("%d
",ans);
}
树
可以转化成上面的问题