ABC-269解题报告

比赛传送门

D. Do use hexagon grid

题目传送门

n2 枚举两个格点,判断是否能直接走,能则连边,最后用 dfs 计算连通块个数。

E. Last Rook

题目传送门

由于不需要考虑斜向的冲突,所以考虑行和列分开二分。以行为例:

如果有若干连续行的棋子数量小于行数,则答案一定在这些行中,以此作为二分的 check。

F. Numbered Checker

题目传送门

显然每一行剩下的数都是一个等差数列。

考虑奇偶行分开计算:对于奇数行,只有奇数列能产生贡献;对于偶数行,只有偶数列能产生贡献。以奇数行为例:

具体地,若输入的四界分别为 u,d,l,r,则只考虑奇数行时,我们将四界缩紧为 u,d,l,r(为方便接下来处理),此时能产生贡献的列数为 lenrow=(rl)/2+1,行数为 lencolumn=(du)/2+1

显然贡献的左上角的值为 s1=(u1)×m+l,右上角为 s2=(u1)×m+r,则第一行的和 sumu=(s1+s2)×lenrow

第二个产生贡献的行(即 u+2 行)的和为 sumu+2=sumu+lenrow×2m,第三行为 sumu+4=sumu+lenrow×4m 以此类推。可以发现每一行都含有一个 sumu 的项,单独提出来,得到 sumu×lencolumn,而每一行新加的贡献为 lenrow×0m+lenrow×2m+lenrow×4m,这也可以很容易得用等差数列求得。

偶数行偶数列的情况同理,由于操作完全相同,可以封装成函数调用两遍。

code:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353;
int add(int a,int b) {return (a+b)%mod;}
int mul(int a,int b) {return a*b%mod;}
signed main() {
	int inv2=(mod+1)/2;
	int n,m,q;
	cin>>n>>m>>q;
	while(q--) {
		int l,r,u,d,ans=0;
		cin>>u>>d>>l>>r;
		auto solve=[&](bool flag) {
			int u1=u,d1=d,l1=l,r1=r;
			if(u1%2==flag) u1++;
			if(d1%2==flag) d1--;
			if(l1%2==flag) l1++;
			if(r1%2==flag) r1--;
			int lenrow=(r1-l1)/2+1,lencol=(d1-u1)/2+1;
			int res=mul(mul(add(add(mul(u1-1,m),l1),add(mul(u1-1,m),r1)),lenrow),inv2);
			(ans+=mul(res,lencol))%=mod;
			(ans+=mul(mul(mul(mul(2*(lencol-1),m),lencol),inv2),lenrow))%=mod;
		};
		solve(0),solve(1);
		cout<<ans<<endl;
	}
	return 0;
}
posted @   曹轩鸣  阅读(38)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起