二维反射容斥:P9366

https://www.luogu.com.cn/problem/P9366

构造循环矩阵,考虑反射容斥和将军饮马

二维反射容斥:P9366_第1张图片

考虑二维不太好做,我们曼哈顿距离转切比雪夫距离,变成一维的情况。

由于棋盘是正方形的,所以循环长度为 2 n + 4 2n+4 2n+4。用多项式快速幂预处理,询问记得考虑正负两个方向。

auto kuai(int T) {
	if(T==0) return atcoder :: Poly({1}); 
	auto p = kuai(T/2); 
	p *= p; 
	for(int i=M; i < p.size(); ++i) p[i-M]+=p[i]; 
	p = p.modxk(M); 
	
	if(T % 2 == 0) return p; 
	
	p = p.mulxk(1) + p.mulxk(M-1);  
	for(int i=M; i < p.size(); ++i) p[i-M]+=p[i]; 
	p = p.modxk(M); 
	
	return p; 
}


signed main()
{
//	freopen("in.txt", "r", stdin);
//	freopen("out.txt", "w", stdout);
//	T=read();
//	while(T--) {
//
//	}
	n=read(); T=read(); q=read(); 
	N=2*(n+1)+2; M=2*N; 
	auto res = kuai(T); 
	auto Go = [&] (int u0, int v0, int u1, int v1) {
		int dx = ( ((u1+v1) - (u0+v0)) % M + M)%M; 
		int dy = ( ((u1-v1) - (u0-v0)) % M + M)%M; 
//		printf("%lld %lld | %lld %lld\n", res[dx].x, res[dy].x, res[(dx+N)%M], res[(dy+N)%M]); 
		return res[dx] * res[dy] + res[(dx+N)%M] * res[(dy+N)%M]; 
	}; 
	while(q--) {
		u0 = read(); v0 = read(); 
		u1 = read(); v1 = read(); 
		auto ans = Go(u0, v0, u1, v1); 
		ans -= Go(u0, v0, N - 2 - u1, v1); 
		ans -= Go(u0, v0, u1, N - 2 - v1); 
		ans += Go(u0, v0, N - 2- u1, N - 2 - v1); 
		printf("%lld\n", ans.x); 
	}
	return 0;
}

你可能感兴趣的:(容斥,反射容斥)