ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[2021.8纪中集训Day5]

2021-08-14 09:02:30  阅读:214  来源: 互联网

标签:GCC int 2021.8 top Day5 stack 纪中 pragma optimize


目录

[2021.8纪中集训Day5] 

前言

今天的题都比较水,T1直接模拟,T2是比较基础的树形DP,T3大暴力,T4相关的内容学过也不难,简单的题解不说具体思路了


4764. 【NOIP2016提高A组模拟9.9】Brothers

题目

代码

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int read() {
	int re = 0;
	char c = getchar();
	bool negt = false;
	while(c < '0' || c > '9')
		negt |= (c == '-') , c = getchar();
	while(c >= '0' && c <= '9')
		re = (re << 1) + (re << 3) + c - '0' , c = getchar();
	return negt ? -re : re;
}

const int N = 110 , M = 110;
int n , m , p , k;
int map[N][M];
int tmp[N][M];

const int f[4][2] = {0,1 , 0,-1 , 1,0 , -1,0};
int main() {
	p = read() , n = read() , m = read() , k = read();
	for(int i = 1 ; i <= n ; i++)
		for(int j = 1 ; j <= m ; j++)
			map[i][j] = read();
	
	for(int _ = 1 ; _ <= k ; _++) {
		memcpy(tmp , map , sizeof(map));
		for(int i = 1 ; i <= n ; i++)
			for(int j = 1 ; j <= m ; j++)
				for(int l = 0 ; l < 4 ; l++) {
					int x = i + f[l][0] , y = j + f[l][1];
					if(map[x][y] == (map[i][j] + 1) % p)
						tmp[x][y] = map[i][j];
				}
		memcpy(map , tmp , sizeof(map));
	}
	
	for(int i = 1 ; i <= n ; i++) {
		for(int j = 1 ; j <= m ; j++)
			printf("%d " , tmp[i][j]);
		putchar('\n');
	}
	return 0;
}

4765. 【NOIP2016提高A组模拟9.9】Crisis

题目

思路

设\(f_i\)表示第\(i\)个人递交申请需要的工人递交申请的数量的最小值,特殊地,如果\(i\)是叶子结点(工人),\(f_i=1\).显然,对于其他结点,直接将按子结点的\(f\)排序,选最小的若干个,使其至少占子节点数量的\(T\%\)即可,\(f_i\)就是这些选出来的\(f\)的和.

如果输入是一条链,是会爆栈的,因此我用了类似拓扑排序的方法枚举点.

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
int read() {
	int re = 0;
	char c = getchar();
	bool negt = false;
	while(c < '0' || c > '9')
		negt |= (c == '-') , c = getchar();
	while(c >= '0' && c <= '9')
		re = (re << 1) + (re << 3) + c - '0' , c = getchar();
	return negt ? -re : re;
}

const int N = 100010;

struct EDGE {
	int to , nxt;
}son[N];
int head[N];
void addson(int fa , int s) {
	static int cnt = 0;
	++cnt;
	son[cnt].to = s , son[cnt].nxt = head[fa] , head[fa] = cnt;
}

int n , t;
int ind[N];
int f[N];

int tmp[N] , sonnum;
int fa[N];
int main() {
	n = read() , t = read();
	for(int i = 1 ; i <= n ; i++) {
		addson(fa[i] = read() , i);
		++ind[fa[i]];
	}
	
	
	queue <int> q;
	for(int i = 0 ; i <= n ; i++)
		if(ind[i] == 0)
			q.push(i);
	while(!q.empty()) {
		int u = q.front();
		q.pop();
		if(head[u] == 0)
			f[u] = 1;
		else {
			sonnum = 0;
			for(int i = head[u] ; i ; i = son[i].nxt) {
				int v = son[i].to;
				tmp[++sonnum] = f[v];
			}
			sort(tmp + 1 , tmp + sonnum + 1);
			for(int i = 1 ; i <= sonnum ; i++) {
				f[u] += tmp[i];
				if(1.0 * i / sonnum >= t * 0.01)
					break;
			}
		}
		
		--ind[fa[u]];
		if(ind[fa[u]] == 0)
			q.push(fa[u]);
	}
	
	cout << f[0];
	return 0;
}

4766. 【NOIP2016提高A组模拟9.9】Word

题目

代码

这个代码没经过后期优化,跑得比较慢,故开了火车头,不会有人卡常吧,不得不说,火车头真的快,7s直接降到1s

#pragma GCC optimize(3)
#pragma GCC target("avx")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#pragma GCC optimize(2)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;
int read() {
	int re = 0;
	char c = getchar();
	bool negt = false;
	while(c < '0' || c > '9')
		negt |= (c == '-') , c = getchar();
	while(c >= '0' && c <= '9')
		re = (re << 1) + (re << 3) + c - '0' , c = getchar();
	return negt ? -re : re;
}


typedef unsigned long long ulint ;
typedef vector<ulint> VecTy;
const int N = 40 , LEN = 60;

inline ulint hash_(char* s , int len) {
	ulint key = 0;
	for(int i = 0 ; i < len ; i++)
		key = key * 131 + (int)s[i];
	return key;
}
void trans(char *s , int len , int d , VecTy &vec) {
	if(d >= 0)
		vec.push_back(hash_(s , len));
	if(d >= 1) {
		for(int i = 0 ; i < len ; i++) {
			for(int j = 'a' ; j <= 'z' ; j++)
				if(s[i] != j) {
					int tmp = s[i];
					s[i] = j;
					vec.push_back(hash_(s , len));
					s[i] = tmp;
				}
		}
	}
	if(d >= 2) {
		for(int i = 0 ; i < len ; i++)
			for(int j = i + 1 ; j < len ; j++)
				for(int x = 'a' ; x <= 'z' ; x++)
					for(int y = 'a' ; y <= 'z' ; y++)
						if(s[i] != x && s[j] != y) {
							int tmp1 = s[i] , tmp2 = s[j];
							s[i] = x , s[j] = y;
							vec.push_back(hash_(s , len));
							s[i] = tmp1 , s[j] = tmp2;
						}
	}
}

void print(char *s , int len) {
	for(int i = 0 ; i < len ; i++)
		putchar(s[i]);
	putchar('\n');
}
void unhash(char *s , int len , int d , ulint key) {
	if(d >= 0) {
		if(hash_(s , len) == key)	print(s , len);
	}
	if(d >= 1) {
		for(int i = 0 ; i < len ; i++) {
			for(int j = 'a' ; j <= 'z' ; j++)
				if(s[i] != j) {
					int tmp = s[i];
					s[i] = j;
					if(hash_(s , len) == key)	print(s , len);
					s[i] = tmp;
				}
		}
	}
	if(d >= 2) {
		for(int i = 0 ; i < len ; i++)
			for(int j = i + 1 ; j < len ; j++)
				for(int x = 'a' ; x <= 'z' ; x++)
					for(int y = 'a' ; y <= 'z' ; y++)
						if(s[i] != x && s[j] != y) {
							int tmp1 = s[i] , tmp2 = s[j];
							s[i] = x , s[j] = y;
							if(hash_(s , len) == key)	print(s , len);
							s[i] = tmp1 , s[j] = tmp2;
						}
	}
}

int l , d;
int n;
char s[N][LEN];
int len[N];

int main() {
	cin >> l >> d >> n;
	for(int i = 1 ; i <= n ; i++) {
		s[i][++len[i]] = getchar();
		while((s[i][len[i]] < 'a' || s[i][len[i]] > 'z') && s[i][len[i]] != ' ')
			s[i][len[i]] = getchar();
		while(s[i][len[i]] >= 'a' && s[i][len[i]] <= 'z' || s[i][len[i]] == ' ')
			s[i][++len[i]] = getchar();
		--len[i];
	}

	VecTy key;
	for(int j = 1 ; j + l - 1 <= len[1] ; j++)
		trans(s[1] + j , l , d , key);

	for(int i = 2 ; i <= n ; i++) {
		VecTy cur , tmp;
		for(int j = 1 ; j + l - 1 <= len[i] ; j++)
			trans(s[i] + j , l , d , cur);

		sort(cur.begin() , cur.end());
		unique(cur.begin() , cur.end());

		int size = key.size();
		for(int j = 0 ; j < size ; j++) {
			int left = 0 , r = cur.size() - 1;
			bool find = false;
			while(left <= r) {
				int mid = (left + r) / 2;
				if(cur[mid] == key[j]) {
					find = true;
					break;
				} else if(cur[mid] < key[j])
					left = mid + 1;
				else
					r = mid - 1;
			}
			if(find)
				tmp.push_back(key[j]);
		}
		key.clear();
		key = tmp;
	}

	for(int i = 0 ; i < key.size() ; i++) {
		for(int j = 1 ; j + l - 1 <= len[1] ; j++)
			unhash(s[1] + j , l , d , key[i]);

	}
	return 0;
}

4769. 【GDOI2017模拟9.9】graph

题目

思路

首先,题目要我们判定二分图,那我们就从二分图的判定入手尝试解决这的问题

二分图的判定-带权并查集

学二分图的时候我们用染色法可以判断二分图,但我们不可能每次都跑一遍全图,但书上应该还有一句话

一张无向图是二分图,当且仅当图中不存在寄环(长度为奇数的环).

这样判定比染色法容易维护得多.

加入一条边,图中是否形成一个环,用普通并查集就可以.

寄环呢? 同样,首先要在加入新边之前边的两个端点本来就连通,如果这两个点的原来距离是偶数,那加入该边后,就会出现奇环.

那如何判断两点距离是否为偶数呢?

我们引入带权并查集.

设\(dist_i\)表示图中\(i\)到\(father_i\)的距离的奇偶性,如果为\(1\),说明距离为奇数,为\(0\)则是偶数.

所以,加边的时候:

//UF:Union-Find,ed:要加入的边
namespace UF {
	int fa[N];
	int dep[N];
	int dist[N];
	void init() {
		memset(dist , 0 , sizeof(dist));
		memset(stack , 0 , sizeof(stack));
		top = 0;
		for(int i = 1 ; i <= n ; i++)
			fa[i] = i;
	}
	int findroot(int x) {//不能路径压缩(后面要支持加删边操作)
		return fa[x] == x ? x : findroot(fa[x]);
	}
	int DistToRoot(int x) {
		return fa[x] == x ? 0 : dist[x] ^ DistToRoot(fa[x]);
	}
	void uni(int x , int y , int dis) {
		fa[x] = y;
		dist[x] = dis;
	}
}
//加边时
			int u = UF::findroot(ed.u) , v = UF::findroot(ed.v);
			int dist = UF::DistToRoot(ed.u) ^ UF::DistToRoot(ed.v) ^ 1;
			if(u != v)
				UF::uni(u , v , dist);

加删边操作-CDQ分治&并查集的撤销

CDQ分治

设边类型:

struct EDGE {
	int u , v , l , r;//u,v连接的两个点, l,r边的有效时间为[l,r]
};

有效时间:

加入边在第\(i\)次操作被加入,在第\(j\)​次被删除,则l=i , r=j-1,把边按\(l,r\),像线段树一样下传就好.

其实这也是本蒟蒻第一次写CDQ分治,所以代码上可能会有问题.

并查集的撤销

既然要撤销,那一次并查集操作就不能涉及到多个点的修改,所以路径压缩是不行的,那我们就按秩合并,用栈记录修改的结点.

namespace UF {
	int fa[N];
	int dep[N];
	int dist[N];
	int stack[N] , top;
	void init() {
		memset(dist , 0 , sizeof(dist));
		memset(stack , 0 , sizeof(stack));
		top = 0;
		for(int i = 1 ; i <= n ; i++)
			fa[i] = i;
	}
	
	int findroot(int x) {
		return fa[x] == x ? x : findroot(fa[x]);
	}
	int DistToRoot(int x) {
		return fa[x] == x ? 0 : dist[x] ^ DistToRoot(fa[x]);
	}
	
	void uni(int x , int y , int dis) {
		if(dep[x] > dep[y])
			swap(x , y);
		if(dep[x] == dep[y])
			++dep[y] , stack[++top] = -y;//正负数表示不同的修改类型,这里负数表示该点深度加了1,整数表示该点父节点发生了变化(深度肯定也要跟着变)
		fa[x] = y;
		dist[x] = dis;
		stack[++top] = x;
	}
	void earse(int now) {//撤销now到top的所有操作,now是栈的某个位置
		for( ; top > now ; --top) {
			if(stack[top] < 0)
				--dep[-stack[top]];
			else
				fa[stack[top]] = stack[top] , dep[stack[top]] = 0;
		}
	}
}

代码

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
int read() {
	int re = 0;
	bool negt = false;
	char c = getchar();
	while(c < '0' || c > '9')
		negt |= (c == '-') , c = getchar();
	while(c >= '0' && c <= '9')
		re = (re << 1) + (re << 3) + c - '0' , c = getchar();
	return negt ? -re : re;
}

const int N = 300010;

struct EDGE {
	int u , v , l , r;
};
EDGE make_edge(int u , int v , int l , int r) {
	EDGE tmp;
	tmp.u = u , tmp.v = v , tmp.l = l , tmp.r = r;
	return tmp;
}

int n , m;
namespace UF {
	int fa[N];
	int dep[N];
	int dist[N];
	int stack[N] , top;
	void init() {
		memset(dist , 0 , sizeof(dist));
		memset(stack , 0 , sizeof(stack));
		top = 0;
		for(int i = 1 ; i <= n ; i++)
			fa[i] = i;
	}
	
	int findroot(int x) {
		return fa[x] == x ? x : findroot(fa[x]);
	}
	int DistToRoot(int x) {
		return fa[x] == x ? 0 : dist[x] ^ DistToRoot(fa[x]);
	}
	
	void uni(int x , int y , int dis) {
		if(dep[x] > dep[y])
			swap(x , y);
		if(dep[x] == dep[y])
			++dep[y] , stack[++top] = -y;
		fa[x] = y;
		dist[x] = dis;
		stack[++top] = x;
	}
	void earse(int now) {
		for( ; top > now ; --top) {
			if(stack[top] < 0)
				--dep[-stack[top]];
			else
				fa[stack[top]] = stack[top] , dep[stack[top]] = 0;
		}
	}
}

bool ans[N];
void CDQ_divide(int l , int r , vector<EDGE> edset) {
	int mid = (l + r) / 2;
	int now = UF::top;
	vector<EDGE> Ledge , Redge;
	for(int i = 0 , size = edset.size() ; i < size ; i++) {
		EDGE ed = edset[i];
		if(ed.l <= l && ed.r >= r) {
			int u = UF::findroot(ed.u) , v = UF::findroot(ed.v);
			int dist = UF::DistToRoot(ed.u) ^ UF::DistToRoot(ed.v) ^ 1;
			if(u != v)
				UF::uni(u , v , dist);
			else if(dist & 1) {//加入ed边后出现寄环,不能构成二分图
				for(int j = l ; j <= r ; j++)
					ans[j] = false;
				UF::earse(now);
				return;
			}
		} else {
			if(ed.r <= mid && ed.r >= l)
				Ledge.push_back(ed);
			else if(ed.l > mid && ed.l <= r)
				Redge.push_back(ed);
			else
				Ledge.push_back(ed) , Redge.push_back(ed);
				
		}
	}
	if(l != r)
		CDQ_divide(l , mid , Ledge) , CDQ_divide(mid + 1 , r , Redge);
	UF::earse(now);
}

int main() {
	freopen("graph.in" , "r" , stdin);
	freopen("graph.out" , "w" , stdout);
	
	n = read() , m = read();
	vector <EDGE> edset;
	for(int i = 1 ; i <= m ; i++) {
		if(read() == 1) {
			int u = read() + 1 , v = read() + 1;
			edset.push_back(make_edge(u , v , i , m));
		} else {
			edset[read()].r = i - 1;
		}
	}
	
	
	UF::init();
	for(int i = 1 ; i <= m ; i++)
		ans[i] = true;
	CDQ_divide(1 , m , edset);
	
	for(int i = 1 ; i <= m ; i++)
		puts(ans[i] ? "YES" : "NO");
	return 0;
}

标签:GCC,int,2021.8,top,Day5,stack,纪中,pragma,optimize
来源: https://www.cnblogs.com/dream1024/p/15139834.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有