2022icpc网络赛第二场:K Black and White Painting

题意:

爱丽丝有一块画布,最初是白色的,她想在上面画画。
Alice将执行n个操作,有两种类型的操作:
选择一个坐标(x,y),然后绘制一个以(x,y)为中心,边长为2的正方形,操作完成后该区域将变为黑色。
选择一个坐标(x,y),然后绘制以(x,y)为圆心,半径为1的圆的范围,操作完成后该区域变为黑色。
经过n次操作后,Alice想知道画布黑色部分的周长。

思路:

我们发现绘制圆和正方形只会影响四个方格,因此我们可以将其的影响先记录于每个方格中,然后最后遍历所有方格算出总周长。

对于每个方格我们需要知道的有,有无正方形对其产生影响,有无圆对其产生影响,方格的四条边是否处于某个图形之内。

有以下几个注意事项:

1.圆和正方形同时对方格产生影响时,正方形优先

2.正方形的影响是,未被包裹于图形中方格边的数量(注意需要判断相邻方格,防止出现两个正方形拼起来依然计算中间边长的情况)

代码:

//#include<bits/stdc++.h>
#include <iostream>
#include <algorithm>
#include <cstring>
#include<vector>
#include<queue>
#include<stack>
#include<bitset>
#include<set>
#include<map>
#include <math.h>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <iomanip>
#include <vector>
//#include <unordered_set>
//#include <unordered_map>
#include <string>
#include <stack>
#include <cassert>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
using db = double;
typedef pair<ll, ll> pll;
#define edl '\n' 
#define SPO(n) fixed << setprecision(n)
const double PI = acos(-1);
#define MAXN 100005
ll MAX = 0x3f3f3f3f3f3f3f3fll;
ll MIN = -MAX;

const int mod = 998244353;
const int N = 1e6 + 10;
ll fc[N], nn[N], NN[N];

ll n, m;

string s;

// 欧拉降幂

int phi(int n)
{
	int res = n;
	for (int i = 2; i * i <= n; i++)
	{
		if (n % i == 0)
		{
			res = res - res / i; // 不能是res*(1-1/i);
			while (n % i == 0)
				n /= i;
		}
	}
	if (n > 1)
		res = res - res / n;
	return res;
}

// 快速幂优化
ll quick_pow(ll a, ll b, ll md)
{
	ll ans = 1;
// ll pp = phi(md);
// if(b >= pp) b = b % pp + pp;
	while (b)
	{
		if (b & 1)
			ans = (ans * a) % md;
		b >>= 1;
		a = (a * a) % md;
	}
	return ans;
}

// 逆元函数 公式为 (a/b)%mod=(a*b^(mod-2))%mod
ll inv(ll a, ll b, ll md)
{
	return (a * quick_pow(b, md - 2, md)) % md;
}
/***
  注意事项 逆元函数的使用 a必须能整除b 并且mod为质数
 **/

void CC(ll md)
{
	fc[0] = nn[0] = NN[0] = 1;
	for (int i = 1; i <= N - 2; i++)
		fc[i] = fc[i - 1] * i % md;
	NN[N - 2] = quick_pow(fc[N - 2], md - 2, md);
	for (int i = N - 2 - 1; i >= 1; i--)
		NN[i] = NN[i + 1] * (i + 1) % md;
	for (int i = 1; i <= N - 2; i++)
		nn[i] = NN[i] * fc[i - 1] % md;
}

ll C(ll n, ll m)
{
	if (n < m || n < 0 || m < 0)
		return 0;
	return fc[n] * NN[m] % mod * NN[n - m] % mod;
}

struct QWQ
{
	ll s1,s2,s3,s4;
	ll ok;
	ll sum;
	ll sum1;
}a[1000][1000];

ll op;

map<pair<ll,ll>,ll>mp1;
map<pair<ll,ll>,ll>mp2;
ll x,y;

void Solve()
{
	cin >> n;
	for(int i = 1; i <= n; i ++ )
	{
		cin >> op;
		if(op == 1)
		{
			cin >> x >> y;
			x += 200;
			y += 200;
			if(mp1[{x,y}]) continue;
			mp1[{x,y}] = 1;
			a[x][y].ok = a[x + 1][y].ok = a[x + 1][y + 1].ok = a[x][y + 1].ok = 1;
			a[x][y].s2 = a[x][y].s3 = 1;
			a[x + 1][y].s1 = a[x + 1][y].s2 = 1;
			a[x + 1][y + 1].s1 = a[x + 1][y + 1].s4 = 1;
			a[x][y + 1].s4 = a[x][y + 1].s3 = 1;
			a[x][y].sum1 ++;
			a[x + 1][y].sum1 ++;
			a[x][y + 1].sum1 ++;
			a[x + 1][y + 1].sum1 ++;
		}
		else
		{
			cin >> x >> y;
			x += 200;
			y += 200;
			if(mp2[{x,y}]) continue;
			mp2[{x,y}] = 1;
			a[x][y].ok = a[x + 1][y].ok = a[x + 1][y + 1].ok = a[x][y + 1].ok = 1;
			a[x][y].s2 = a[x][y].s3 = 1;
			a[x + 1][y].s1 = a[x + 1][y].s2 = 1;
			a[x + 1][y + 1].s1 = a[x + 1][y + 1].s4 = 1;
			a[x][y + 1].s4 = a[x][y + 1].s3 = 1;
			a[x][y].sum ++;
			a[x + 1][y].sum ++;
			a[x][y + 1].sum ++;
			a[x + 1][y + 1].sum ++;
		}
	}
	ll ans1,ans2;
	ans1 = ans2 = 0;
	for(int i = 100; i <= 400; i ++ )
	{
		for(int j = 100; j <= 400; j ++ )
		{
			if(a[i][j].ok)
			{
				ll sum = a[i][j].s4 + a[i][j].s1 + a[i][j].s3 + a[i][j].s2;
				if(sum == 4) continue;
				if(a[i][j].sum1)
				{
					if(!a[i][j].s4)
					{
						int xx = i;
						int yy = j - 1;
						if(a[xx][yy].sum1 && !a[xx][yy].s2) ;
						else ans1 ++;
					}
					if(!a[i][j].s1)
					{
						int xx = i - 1;
						int yy = j;
						if(a[xx][yy].sum1 && !a[xx][yy].s3) ;
						else ans1 ++;
					}
					if(!a[i][j].s2)
					{
						int xx = i;
						int yy = j + 1;
						if(a[xx][yy].sum1 && !a[xx][yy].s4) ;
						else ans1 ++;
					}
					if(!a[i][j].s3)
					{
						int xx = i + 1;
						int yy = j;
						if(a[xx][yy].sum1 && !a[xx][yy].s1) ;
						else ans1 ++;
					}
				}
				else if(a[i][j].sum) ans2 = (ans2 + inv(1,sum,mod)) % mod;
			}
		}
	}
	cout << ans1 << " " << ans2 << edl;
}


int main()
{
	std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	//#ifndef ONLINE_JUDGE
	//freopen("cin.txt","r",stdin);
	//freopen("cout.txt","w",stdout);
	//#endif
	ll t = 1;
	//cin >> t;
	// 组合数
	CC(mod);
	while(t -- )
		Solve();
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值