2021-07-12 部分集训题目题解

一时暴力一时爽,一直暴力一直爽(两个亿

染色

题目传送门

Description

Solution

我们考虑先染斜对角线再染行,那么可以发现的是,如果一个斜对角线经过的行都染了色,那选不选这条线都不会有影响。

所以,我们假设一个斜对角线经过行的区间是 ([l_i,r_i]),那么问题就是选出一些区间,并在这些区间的并中选出一些元素,使得没有一个被选中的区间中每个位置的元素都被选中。可以看出,选元素就是选哪些行被染色。

这个分类讨论然后做个前缀和,复杂度 (Theta(n^3))

Code

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define MAXN 2005

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c != ' ' && c != '
') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> void chkmax (T &a,T b){a = max (a,b);}
template <typename T> void chkmin (T &a,T b){a = min (a,b);}

#define pii pair<int,int>
#define se second
#define fi first
vector <pii> S;

int n,m,mod,pw[MAXN],f[MAXN][MAXN],pre[MAXN][MAXN];

int mul (int a,int b){return 1ll * a * b % mod;}
int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
void Add (int &a,int b){a = add (a,b);}

signed main(){
	freopen ("coloring.in","r",stdin);
	freopen ("coloring.out","w",stdout);
	read (n,m,mod),S.resize (n + m + 1);int tot = 0;
	for (Int i = 1;i <= n + m - 1;++ i) ++ tot,S[i] = {max (1,i - m + 1),min (n,i)};
	pw[0] = 1;for (Int i = 1;i <= max (n,m);++ i) pw[i] = add (pw[i - 1],pw[i - 1]);
	for (Int i = 0;i <= n;++ i) pre[0][i] = 1;
	for (Int i = 1;i <= tot;++ i){
		for (Int j = 0;j <= S[i].se - S[i].fi;++ j){
			for (Int k = 0;k < i;++ k){
				if (S[i].se - j > S[k].se){
					if (S[k].se < S[i].fi) Add (f[i][j],mul (pre[k][n],pw[S[i].se - S[i].fi - j]));
					else Add (f[i][j],mul (pre[k][n],pw[S[i].se - S[k].se - j - 1]));
				}
				else Add (f[i][j],f[k][j + S[k].se - S[i].se]);
			}
		}
		for (Int j = 0;j <= n;++ j) pre[i][j] = add (j ? pre[i][j - 1] : 0,f[i][j]);
	}
	int ans = 0;
	for (Int i = 0;i <= tot;++ i) Add (ans,pre[i][n]);
	write (ans),putchar ('
');
	return 0;
}

生命游戏

题目传送门

Description

Solution

对于 (n=1) 的情况可以想到的是,每时每刻它存活格子都是斜 (45^circ)

对于 (n=2) 的情况,可以想到如果两个横纵坐标和的奇偶性相同,那么两者才会产生影响,影响如下:

可以看出,对于时刻 (t) ,贡献就是 ((a+t) imes (b+t)) 的形式。

考虑对此进行拓展,可以想到,从两个点相交到另两个点相交这一段时间的贡献显然就是关于 (t) 的三次函数形式。那么我们就可以用扫描线求出一个时刻的贡献,然后暴力插值。

复杂度 (Theta(n^4+qlog n))

Code

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define inv2 499122177
#define inv6 166374059
#define mxv 1000000000
#define mod 998244353
#define int long long
#define MAXN 205

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c != ' ' && c != '
') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> void chkmax (T &a,T b){a = max (a,b);}
template <typename T> void chkmin (T &a,T b){a = min (a,b);}

#define fi first
#define se second
#define pii pair<int,int>

int n,q;
int mul (int a,int b){return 1ll * a * b % mod;}
int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
void Add (int &a,int b){a = add (a,b);}
void Sub (int &a,int b){a = dec (a,b);}

vector <pii> vp[2];

struct node{
	int x,l,r;
	bool t;
};

int a[MAXN],y[MAXN];
int calc (int o,int d){//计算奇偶性为t的点在d时刻的贡献
	vector <node> v;
	memset (a,0,sizeof (a));
	int uni = 0,res = 0,tmp = 0;
	for (pii it : vp[o]){
		int yl = it.se - (d + 1 >> 1),yr = it.se + (d >> 1) + 1;
		y[++ uni] = yl,y[++ uni] = yr,
		v.push_back (node{it.fi - (d + 1 >> 1),yl,yr,1}),
		v.push_back (node{it.fi + (d >> 1) + 1,yl,yr,0});
	}
	sort (y + 1,y + uni + 1),uni = unique (y + 1,y + uni + 1) - y - 1,sort (v.begin(),v.end(),[](node s1,node s2){return s1.x < s2.x;});
	for (Int i = 0;i < v.size();++ i){
		v[i].l = lower_bound (y + 1,y + uni + 1,v[i].l) - y,v[i].r = lower_bound (y + 1,y + uni + 1,v[i].r) - y;
		for (Int j = v[i].l;j < v[i].r;++ j) 
			if (v[i].t){
				if (!a[j]) tmp += (y[j + 1] - y[j]);
				a[j] ++;
			}
			else{
				a[j] --;
				if (!a[j]) tmp -= (y[j + 1] - y[j]);
			}
		if (i != v.size()) Add (res,mul (tmp,v[i + 1].x - v[i].x));
	}
	return res;
}

struct fuc{
	int y[4];
	fuc(){for (Int i = 0;i < 3;++ i) y[i] = 0;}
	void makeit (){y[0] = mul (mod - inv6,y[0]),y[1] = mul (inv2,y[1]),y[2] = mul (mod - inv2,y[2]),y[3] = mul (inv6,y[3]);}
	int getit (int d){
		int pl[4] = {},pr[4] = {},res = 0;
		pl[0] = 1;for (Int i = 0;i < 3;++ i) pl[i + 1] = mul (pl[i],dec (d,i));
		pr[3] = 1;for (Int i = 3;i > 0;-- i) pr[i - 1] = mul (pr[i],dec (d,i));
		for (Int i = 0;i <= 3;++ i) Add (res,mul (mul (pl[i],pr[i]),y[i]));
		return res;
	}
};

fuc getit (int o,int s,int l,int r){
	fuc t;
	for (Int i = l;i <= r && i <= l + 3;++ i) Add (s,calc (o,i)),t.y[i - l] = s;
	t.makeit();return t;
}

vector <int> tim[2];
vector <fuc> sht[2];

void buildit (int o){
	tim[o].push_back (0),tim[o].push_back (mxv + 1);
	for (pii it1 : vp[o]) for (pii it2 : vp[o]) tim[o].push_back (max (abs (it1.fi - it2.fi),abs (it1.se - it2.se)));
	sort (tim[o].begin(),tim[o].end()),tim[o].erase (unique (tim[o].begin(),tim[o].end()),tim[o].end());
	fuc t;for (Int i = 0,lst = 0;i < tim[o].size() - 1;++ i) t = getit (o,lst,tim[o][i],tim[o][i + 1] - 1),sht[o].push_back (t),lst = t.getit (tim[o][i + 1] - 1 - tim[o][i]);
}
 
int fuckit (int o,int T){
	int pos = upper_bound (tim[o].begin(),tim[o].end(),T) - tim[o].begin() - 1;
	return sht[o][pos].getit (T - tim[o][pos]);
}
 
signed main(){
	freopen ("lifegame.in","r",stdin);
	freopen ("lifegame.out","w",stdout);
	read (n,q);
	for (Int i = 1;i <= n;++ i){
		int x,y;read (x,y);
		vp[x + y & 1].push_back ({x + y >> 1,x + mxv - y >> 1});
	}
	buildit (0),buildit (1);
	while (q --> 0){
		int T;read (T);
		write (add (fuckit (0,T),fuckit (1,T))),putchar ('
');
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Dark-Romance/p/15003793.html