2022.9.24———【CSP-S模拟10】游寄

\(Preface\)

\(Rank42/42\) 垫底了我超

\(0pts + 12pts + 0pts + 0pts = 12pts\)

T1 欧几里得的噩梦,T2 清扫,T3 购物,T4 ants

\(\mathfrak{T1}\ 欧几里得的噩梦\)

上来就干了一个线性基,我没学。

他说的全集就是本来所有的能异或出来的所有数,那么可能会有一些数在里面是可以被替代的,我们就是要把这些数扔出去,使得剩下的数能够异或出来的数和全集相同。

对于每个数给出的 \(x\text{,}y\),先判断一下 \(x\)\(y\) 是否是属于同一个联通块的,如果是那么就说明他们两个合成的数已经出现过了,无需将此数加入子集,因为他加进去后并没有贡献。

然后再用并查集将 \(x\)\(y\) 连起来继续跑就行了。

T1


#include <iostream>
#define GMY (520&1314)
#define FBI_OPENTHEDOOR(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout);
#define int long long
#define re register int
#define char_phi signed
#define DMARK cerr << "###"
#define _ ' '
#define Endl cout << '\n'
#define Dendl cerr << '\n'
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define N 500005
#define P 1000000007
#define mod %
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL);}
int n, m;
int fa[N], ans[N];
int find(int x){return ((fa[x] == x) ? (x) : (fa[x] = find(fa[x])));}
inline int ksm(int A, int B){
	int res(1);
	while (B != 0){
		if ((B & 1) == 1) res = res * A mod P;
		A = A * A mod P;
		B >>= 1;
	}
	return res;
}
inline void work(){
	cin >> n >> m;
	for (re i = 1 ; i <= m ; ++ i)
		fa[i] = i;
	fa[m+1] = m+1;
	for (re i = 1, opt, x, y ; i <= n ; ++ i){
		cin >> opt;
		if (opt == 1)
			{cin >> x; y = m+1;}
		else 
			cin >> x >> y;
		x = find(x), y = find(y);
		fa[x] = y;
		if (x != y)
			ans[++ ans[0]] = i;
	}
	cout << ksm(2, ans[0]) << _ << ans[0] << '\n';
	for (re i = 1 ; i <= ans[0] ; ++ i)
		cout << ans[i] << _;
	Endl;
}
// #define IXINGMY
char_phi main(){
	#ifdef IXINGMY
		FBI_OPENTHEDOOR(a);
	#endif
	Fastio_setup();
	work();
	return GMY;
}

\(\mathfrak{T2}\ 清扫\)

再次解释题意

你能一直扫,并不是你每个叶子组合只能扫一次。

但是我赛时并不这么认为,我就认为你每个叶子组合只能扫一次。听CD讲题的时候一脸蒙。哪来的方程???

但就这还能水到 \(12pts\) 真的震惊(

正解不会,贺题解

建议去看 \(\text{kiritokazuto}\) 的博客dsu

T2
#include <iostream>
#define GMY (520&1314)
#define FBI_OPENTHEDOOR(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout);
#define int long long
#define re register int
#define char_phi signed
#define DMARK cerr << "###"
#define _ ' '
#define Endl cout << '\n'
#define Dendl cerr << '\n'
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define N 100005
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL);}
struct star{int v, nxt;};
int n, star_cnt, rt, Du1;
char isl[N];
int head[N], a[N], sz[N], son[N];
struct star e[N<<1];
inline void star_add(int u, int v){e[++ star_cnt].v=v, e[star_cnt].nxt=head[u], head[u]=star_cnt;}
void GetLeaf(int x, int faer){
	char isleaf(true);
	for (re i = head[x] ; i ; i = e[i].nxt){
		int v = e[i].v;
		if (v == faer)
			continue;
		isleaf = false;
		GetLeaf(v, x);
	}
	if (isleaf == true)
		isl[x] = true;
}
char dfs(int x, int faer){
	if (isl[x] == true)
		{sz[x] = a[x]; return true;}
	for (re i = head[x] ; i ; i = e[i].nxt){
		int v = e[i].v;
		if (v == faer)
			continue;
		if (dfs(v, x) == false)
			return false;
		sz[x] += sz[v];
		if (son[x] == 0 or sz[v] > sz[son[x]])
			son[x] = v;// 重儿子
	}
	if (sz[x] < a[x])
		return false;
	int mx = (sz[son[x]]<<1) - sz[x];
	sz[x] = (a[x]<<1) - sz[x];
	return ((sz[x] >= 0) and (sz[x] >= mx));
}
inline void work(){
	cin >> n;
	for (re i = 1 ; i <= n ; ++ i)
		cin >> a[i];
	for (re i = 1, uu, vv ; i <= n-1 ; ++ i)
		{cin >> uu >> vv; star_add(uu, vv), star_add(vv, uu); Du1 += ((uu == 1) or (vv == 1));}
	char ok;
	if (n == 2)
		goto Special;
	rt = ((Du1 == 1) ? (e[head[1]].v) : (1));
	GetLeaf(rt, 0);
	ok = dfs(rt, 0);
	cout << (((ok == true) and (sz[rt] == 0)) ? ("YES") : ("NO")) << '\n';
	return ;
	Special:{
		cout << ((a[1] == a[2]) ? ("YES") : ("NO")) << endl;
	}
}
// #define IXINGMY
char_phi main(){
	#ifdef IXINGMY
		FBI_OPENTHEDOOR(a);
	#endif
	Fastio_setup();
	work();
	return GMY;
}

\(\mathfrak{T3}\ 购物\)

一个水结论题。

直接打表出规律,发现这玩意与前缀和、\(a_i\) 很有关系,然后直接大胆猜测结论就行了。

结论:如果 \(a_i > sum_{i-1}\),那么就会在 \(sum_{i-1} \sim \frac{a_i - 1}{2}\) 的位置出现空缺。

先初始化答案为 \(sum_n\),然后依次找到空缺并将其减去就行了。

这个结论是有证明的,由 \(\text{SMTwy}\) 给出,但是他现在还没写我去催催他,催成了的话我就把链接挂这里。

总结:

\[ 觉得是规律题的题一定要『排序』还有『大量打表』! \]

T3
#include <iostream>
#include <algorithm>
#include <cmath>
#define GMY (520&1314)
#define FBI_OPENTHEDOOR(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout);
#define re register int
#define char_phi signed
#define DMARK cerr << "###"
#define _ ' '
#define Endl cout << '\n'
#define Dendl cerr << '\n'
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define N 100005
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL);}
/*
	一个水结论题。
*/
long long n, final_ans;
long long a[N], sum[N];
inline void work(){
	cin >> n;
	for (re i = 1 ; i <= n ; ++ i)
		cin >> a[i];
	sort(a+1, a+n+1);
	for (re i = 1 ; i <= n ; ++ i)
		sum[i] = sum[i-1]+a[i];
	final_ans = sum[n];
	for (re i = 1 ; i <= n ; ++ i){
		if (a[i]/2 > sum[i-1])
			final_ans -= ((a[i]-1)/2 - sum[i-1]);
	}
	cout << final_ans << '\n';
}
// #define IXINGMY
char_phi main(){
	#ifdef IXINGMY
		FBI_OPENTHEDOOR(a);
	#endif
	Fastio_setup();
	work();
	return GMY;
}

\(\mathfrak{T4}\ ants\)

我的建议是

这题是原题

就是permu

只不过数据加强了一点

回滚莫队板子

T4
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#define GMY (520&1314)
#define FBI_OPENTHEDOOR(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout);
#define int long long
#define re register int
#define char_phi signed
#define DMARK cerr << "###"
#define _ ' '
#define Endl cout << '\n'
#define Dl cerr << '\n'
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define N 100005
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL);}

int n, Q, top, blocklen;
int a[N], L[N], R[N], ans[N], belong[N];
struct Stack{int pos, w;};
struct Question{
	int l, r, id;
	friend bool operator < (Question A, Question B){
		if (belong[A.l] != belong[B.l])
			return A.l < B.l;
		else 
			return A.r < B.r;// 超 排序锅了
	}
};
struct Question q[N];
struct Stack s[N];

inline void work(){
	cin >> n >> Q; blocklen = sqrt(n);
	for (re i = 1 ; i <= n ; ++ i)
		{cin >> a[i]; belong[i] = (i-1)/blocklen + 1;}
	for (re i = 1 ; i <= Q ; ++ i)
		{cin >> q[i].l >> q[i].r; q[i].id = i;}
	/*cerr.tie(NULL);
	cerr << n << _ << Q << '\n';
	for (re i = 1 ; i <= n ; ++ i)
		cerr << a[i] << '\n';
	for (re i = 1 ; i <= Q ; ++ i)
		cerr << q[i].l << _ << q[i].r << '\n';*/
	sort(q+1, q+Q+1);
	
	/*for (re i = 1 ; i <= Q ; ++ i)
		cerr << belong[q[i].l] << _;
	Dl;*/
	int l(1), r(0), res(0);
	int* it = NULL;
	for (re i = 1 ; i <= Q ; ++ i){
		if (belong[q[i].l] != belong[q[i-1].l]){
			memset(L, 0, sizeof(L)), memset(R, 0, sizeof(R));
			l = r = belong[q[i].l]*blocklen; res = 0;
		}
		while (r < q[i].r){
			r ++;
			L[a[r]] = L[a[r]-1]+1, R[a[r]] = R[a[r]+1]+1;
			int len = L[a[r]]+R[a[r]]-1, lp = a[r]-L[a[r]]+1, rp = a[r]+R[a[r]]-1;
			L[rp] = R[lp] = len;
			res = MAX(res, len);
		}
		int ano(res);
		top = 0;
		for (re j = q[i].l ; j <= MIN(q[i].r, l) ; ++ j){
			L[a[j]] = L[a[j]-1] + 1, R[a[j]] = R[a[j]+1] + 1;
			int len = L[a[j]]+R[a[j]]-1, lp = a[j]-L[a[j]]+1, rp = a[j]+R[a[j]]-1;
			s[++ top] = (Stack){rp, L[rp]}, s[++ top] = (Stack){lp, R[lp]};
			L[rp] = R[lp] = len; ano = MAX(ano, len);
		}
		for (re j = top ; j >= 1 ; -- j){
			if ((j & 1) == 1)
				it = &L[s[j].pos];
			else 
				it = &R[s[j].pos];
			*it = s[j].w;
		}
		for (re j = q[i].l ; j <= MIN(q[i].r, l) ; ++ j)
			L[a[j]] = R[a[j]] = 0;
		ans[q[i].id] = ano;
	}
	for (re i = 1 ; i <= Q ; ++ i)
		cout << ans[i] << '\n';
	Endl;
}
// #define IXINGMY
char_phi main(){
	#ifdef IXINGMY
		FBI_OPENTHEDOOR(a);
	#endif
	Fastio_setup();
	work();
	return GMY;
}
posted @ 2022-09-28 17:19  char_phi  阅读(10)  评论(0)    收藏  举报