我是靠谱客的博主 正直唇膏,最近开发中收集的这篇文章主要介绍ZR19CSP-S赛前冲刺day5A 染色B 乘方C 位运算总结,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

为了保护ZR的版权,这里不提供题目QWQ

http://zhengruioi.com/contest/442 (你进得去吗/xyx)

A 染色

发现对于每个连通块最多剩下一棵树

答案就是 ∑ 边 数 − 点 数 + 1 sum 边数 - 点数 + 1 +1
然后就没了

code:

#include<bits/stdc++.h>
#define N 2000005
using namespace std;
struct edge {
	int v, nxt;
}e[N << 1];
int p[N], eid;
void init() {
	memset(p, -1, sizeof p);
	eid = 0;
}
void insert(int u, int v) {
	e[eid].v = v;
	e[eid].nxt = p[u];
	p[u] = eid ++;
}
int n, m, vis[N], ds, bs, in[N];
void dfs(int u) {
	vis[u] = 1;
	bs += in[u], ds ++;
	for(int i = p[u]; i + 1; i = e[i].nxt) {
		int v = e[i].v;
		if(!vis[v]) dfs(v);
	}
}
int main() {
	init();
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= m; i ++) {
		int u, v;
		scanf("%d%d", &u, &v);
		insert(u, v); in[u] ++;
		insert(v, u); in[v] ++;
	}
	int ans = 0;
	for(int i = 1; i <= n; i ++) if(!vis[i]) {
		bs = 0;
		ds = 0;
		dfs(i);
		bs /= 2;
		ans += bs - ds + 1;
	}
	printf("%d ", ans);
	return 0;
}

B 乘方

首先可以二分答案

然后考虑容斥

对于已选来的集合 ( − 1 ) k ∩ S ( n i )       k 个 (-1)^k cap S(n_i) k个 (1)kS(ni)     k
考虑如何计算
发现就是 S ( l c m ( n i ) ) S(lcm(n_i)) S(lcm(ni))

S ( x ) S(x) S(x) 可以直接用二分 + 快速幂求出来

这样只能拿部分分

发现只和 l c m lcm lcm有关
再考虑DP, f [ i ] 表 示 l c m = i 的 容 斥 系 数 之 和 f[i]表示lcm=i的容斥系数之和 f[i]lcm=i
最后答案就是 ∑ f [ i ] S ( i ) sum f[i]S(i) f[i]S(i)
1要特殊处理一下
然后就没了

code:


#include<bits/stdc++.h>
#define N 65
#define int long long
#define double long double 
using namespace std;
int gcd(int x, int y) {
	return y? gcd(y, x % y) : x;
}
int lcm(int x, int y) {
	return x * y / gcd(x, y);
}
int n, m, a[N], f[N], q;
int qpow(int x, int y) {
	int ret = 1;
	for(; y; y >>= 1, x = x * x) if(y & 1) ret = ret * x;
	return ret;
}
int find(int x, int y) {
	int l = 1, r = pow(1e18, 1.0 / (double)y) + 1;
	while(l + 1 < r) {
		int mid = (l + r) >> 1;
		if(qpow(mid, y) <= x) l = mid;
		else r = mid;
	}
	return l;
}
int calc(int X) {
	int ans = 1;
	for(int i = 1; i <= 60; i ++) ans += (find(X, i) - 1) * f[i];
	return ans;
}
signed main() {
	scanf("%lldn", &q);
	while(q --) {
		memset(f, 0, sizeof f);
		scanf("%lld%lld", &m, &n);
		for(int i = 1; i <= n; i ++) scanf("%lld", &a[i]);
		sort(a + 1, a + 1 + n);
		for(int i = 1; i <= n; i ++) {
			for(int j = 60; j >= 1; j --) 
				if(lcm(j, a[i]) <= 60) f[lcm(j, a[i])] -= f[j];
			f[a[i]] ++;
		}
			
		int l = 0, r = 1e17 + 1;
		while(l + 1 < r) {
			int mid = (l + r) >> 1;
			if(calc(mid) >= m) r = mid;
			else l = mid;
		}
		printf("%lldn", r);	
	}
	
	return 0;
}

C 位运算

大力FWT

注意常数

最好用常数 / 2的那种写法

code:


#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = (1 << 23) + 5;
void fwt_or(ll *a, int len, int opt){
	for(int i = 1; i < len; i <<= 1)
		for(int j = 0; j < len; j += i << 1)
			for(register int k = j; k < j + i; k ++)
				a[i + k] += (ll)opt * a[k];
}
void fwt_and(ll *a, int len, int opt){
	for(int i = 1; i < len; i <<= 1)
		for(int j = 0; j < len; j += i << 1)
			for(register int k = j; k < j + i; k ++)
				a[k] += (ll)opt * a[i + k];
}
 
void fwt_xor(ll *a, int len, int opt){
	for(int i = 1; i < len; i <<= 1)
		for(int j = 0; j < len; j += i << 1)
			for(register int k = j; k < j + i; k ++){
				ll X = a[k], Y = a[k + i];
				a[k] = X + Y, a[k + i] = X - Y;
				if(opt == -1) a[k] = (X + Y) >> 1, a[k + i] = (X - Y) >> 1;
			}
}

int n, opt, cnt[N];
ll f[N], g[N];
int main(){
	scanf("%d%d", &n, &opt);
	int ma = 0;
	for(int i = 1; i <= n; i ++) {
		int x;
		scanf("%d", &x);
		cnt[x] ++;
		f[x] ++;
		ma = max(ma, x);
	}
	int len = (1 << 23);
	//	printf("%dn", len);
	if(opt == 3) {
		fwt_or(f, len, 1);
		for(int i = 0; i < len; i ++) f[i] = f[i] * f[i];
		fwt_or(f, len, -1);
		for(int i = len; i >= 0; i --) if(f[i] - cnt[i] > 0) {printf("%d %lld", i, (f[i] - cnt[i]) / 2); return 0;}			
	}
	
	if(opt == 1) {
		fwt_and(f, len, 1);
		for(int i = 0; i < len; i ++) f[i] = f[i] * f[i];
		fwt_and(f, len, -1);
		for(int i = len; i >= 0; i --) if(f[i] - cnt[i] > 0) {printf("%d %lld", i, (f[i] - cnt[i]) / 2); return 0;}	
	}
	
	if(opt == 2) {
		fwt_xor(f, len, 1);
		for(int i = 0; i < len; i ++) f[i] = f[i] * f[i];
		fwt_xor(f, len, -1);
		for(int i = len; i >= 1; i --) if(f[i]) {printf("%d %lld", i, f[i] / 2); return 0;} 
		printf("0 %lld", (f[0] - n) / 2);
	}	
	
	return 0;
}

总结

速度要提上去

最后

以上就是正直唇膏为你收集整理的ZR19CSP-S赛前冲刺day5A 染色B 乘方C 位运算总结的全部内容,希望文章能够帮你解决ZR19CSP-S赛前冲刺day5A 染色B 乘方C 位运算总结所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(70)

评论列表共有 0 条评论

立即
投稿
返回
顶部