金华3.11

金华3.11

取石子

加强版是CF1033G

首先是不平等博弈,不能算SG值,考虑找规律。

然后可以对A+B取模,因为如果新游戏先手有必胜策略,先手不会去取A+B,后手取了直接模仿,一直按照新策略到后手不得不取A+B。然后按值的大小讨论策略,有点人类智慧。

字符串

容斥最多只能做到\((\sum |S|)^2\),正解可以把反串和正串合成一个AC自动机在上面dp。

网格计数

一条直线的限制:把终点对这条直线翻转一下,那么起点到翻转出来的终点的一条路径唯一对应一条过线的路径,直接减一下

如果有上下两条直线,还是考虑容斥,现在要把路径赋值使得不合法的路径权值是-1,合法的是0。

考虑两个过程:

  1. 一条路径第一次经过 \(y=t\) 时 -1,在这之后经过 \(y=0\) 时 +1,之后重复-1+1
  2. 第一次经过 \(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\n",ans);
}

可以转化成上面的问题

posted @ 2021-03-11 19:08  lcyfrog  阅读(101)  评论(0编辑  收藏  举报