20201103gryz模拟赛解题报告

写在前面

昨天忘写了来补上

T1位运算乱搞一会没搞出来,

打完T4floyd暴力分之后发现T2树状数组可以骗点分

打完T3暴力手模了一遍样例之后发现T3就是个线段树板子

最后就非常愉快的拿到175pts,rank3

T1:U139249 位运算之谜

https://i.cnblogs.com/preference

很显然我并不知道这个公式

因为a&b表示的是都是1的位数,a^b表示的是只有一个是1的位数,

如果都是1,a+b后会进位,否则保留,

所以可推的如上的式子:$a+b=((a&b)<<1)+(a^b) $;

由题意已知\(a&b=y\)\(a+b=x\)

\(a^b=x-2 \times y\);

因为这个数取的是不同位,\(y\)取的是相同位,所以他俩\(&\)起来一定为\(0\)

不为 \(0\) 为不合法

/*
Work by: Suzt_ilymics
Knowledge: ??
Time: O(??)
*/
#include<iostream>
#include<cstdio>
using namespace std;
long long T, x, y;

long long read(){
	long long w = 1, s = 0;
	char ch = getchar();
	while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
	while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0', ch = getchar();
	return s * w;
}

int main()
{
	T = read();
	while(T--){
		x = read(), y = read();
		if((x - 2 * y) < 0 || ((x - 2 * y) & y)) cout<<-1<<endl;
		else cout<<(x - y - y)<<endl;
	}	
	return 0;
}

T2:U139245 游戏

看到数据范围比较小,预处理一个二维前缀和

暴力枚举每个节点i,j,二分找出最长边长即可

二维树状数组的话还是太慢了

/*
Work by: Suzt_ilymics
Knowledge: ??
Time: O(??)
*/
#include<iostream>
#include<cstdio>
using namespace std;
int n, m, K;
int sum[310][310][30];
int a[310][310][30];

int read(){
	int w = 1, s = 0;
	char ch = getchar();
	while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
	while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0', ch = getchar();
	return s * w;
}

bool check(int i, int j, int k, int l){
	for(int a = 1; a <= 26; ++a){
		if(sum[k][l][a] + sum[i - 1][j - 1][a] - sum[i - 1][l][a] - sum[k][j - 1][a] > K) return false;
	}
	return true;
}

int main()
{
	n = read(), m = read(), K = read();
	char x;
	for(int i = 1; i <= n; ++i){
		for(int j = 1; j <= m; ++j){
			cin>>x;
			a[i][j][x - 'a' + 1]++;
			for(int k = 1; k <= 26; ++k){
				sum[i][j][k] = sum[i-1][j][k] + sum[i][j-1][k] - sum[i-1][j-1][k] + a[i][j][k];
			}
		}
	}
	for(int i = 1; i <= n; ++i){
		for(int j = 1; j <= m; ++j){
			int l = 0, r = min(n - i, m - j), ans = 0;
			while(l <= r){
				int mid = (l + r) >> 1;
				if(check(i, j, i + mid, j + mid)){ ans = mid; l = mid + 1; }
				else{ r = mid - 1; }
			}
			printf("%d ", ans + 1);
		}
		puts("");
	}
	return 0;
}

T3:U139247 或和异或

手模样例发现每两个相邻的元素在每次操作后会合并成一个

可以用线段树来维护一下,最后输出树根的答案即可

修改操作对应线段树的单点修改

上传的时候注意判断是or还是xor

/*
Work by: Suzt_ilymics
Knowledge: ??
Time: O(??)
=============================Kersen AK IOI !!!=====================================================
*/
#include<iostream>
#include<cstdio>
#include<cmath>
#define lson i << 1
#define rson i << 1 | 1
using namespace std;
const int MAXN = 131100;
struct Tree{
	long long dep;
	long long sum;
}tree[MAXN << 2];
long long n, Q;
bool flag = 0;
long long a[131080];
int ecm[20] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072};
//long long b[131080];
//int wzd[30];
//long long kersen[30];

long long read(){
	long long s = 0, w = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') w = -1; ch = getchar(); }
	while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0', ch = getchar();
	return s * w;
}

void push_up(int i){
	if(!flag){//如果n是奇数,树是n + 1层,上传的时候奇数深度进行|操作,偶数深度进行^操作 
		if(tree[i].dep % 2){tree[i].sum = (tree[lson].sum | tree[rson].sum);}
		else{tree[i].sum = (tree[lson].sum ^ tree[rson].sum);}
	}
	else{//如果n是偶数,树是n + 1层,上传的时候偶数深度进行|操作,奇数深度进行^操作,与上面相反 
		if(tree[i].dep % 2){tree[i].sum = (tree[lson].sum ^ tree[rson].sum);}
		else{tree[i].sum = (tree[lson].sum | tree[rson].sum);}
	}
}

void build(long long i, long long l, long long r, long long dep){
	tree[i].dep = dep;
	if(l == r) {
		tree[i].sum = a[l];
		return ;
	}
	int mid = (l + r) >> 1;
	build(lson, l, mid, dep + 1), build(rson, mid + 1, r, dep + 1);
	push_up(i);
	return ;
}

void add(long long i ,long long l, long long r, long long x, long long k){
	if(l == x && r == x) {
		tree[i].sum = k;
		return ;
	}
	int mid = (l + r) >> 1;
	if(x <= mid) add(lson, l, mid, x, k);
	else add(rson, mid + 1, r, x, k);
	push_up(i);
	return ;
}

int main()
{
//	freopen("xor.in","r",stdin);
//	freopen("xor.out","w",stdout);
	n = read(), Q = read();
	if(n%2 == 0) flag = 1;//如果n是偶数,标记一下 
	for(long long i = 1; i <= ecm[n]; ++i) a[i] = read();
	build(1, 1, ecm[n], 1);
	for(long long i = 1, x, k; i <= Q; ++i){
		x = read(), k = read();
		add(1, 1, ecm[n], x, k);
		cout<<tree[1].sum<<endl;
	}
	return 0;
}

T4:U139253 链接

因为边的长度随编号的增加而增加,且前i条边的和一定不会超过第i+1条边

根据这个性质,在读入边的时候直接建出最小生成树,就求完了各个点的最短路

考虑u,v这两个节点 ,假设我们已经知道了u,那么我们可以通过如下式子推得v

\[ans_{v} = ans_{u} - siz_{v} \times e_{i}.w + (point - siz_{v}) \times e_{i}.w \]

最后求一下和就是答案

/*
Work by: Suzt_ilymics
Knowledge: ??
Time: O(??)
*/
#include<iostream>
#include<cstdio>
#define int long long
using namespace std;
const int MAXN = 1e5+5;
const int MAXM = 2e5+5;
const int mod = 1000000007;
struct edge{
	int to, w, nxt;
}e[MAXM];
int head[MAXN], num_edge;
int n, m, point;
int dis[MAXN], fath[MAXN], f[MAXN], siz[MAXN];
bool type[MAXN];

int read(){
	int w = 1, s = 0;
	char ch = getchar();
	while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
	while(ch >= '0' && ch <= '9') s = s* 10 + ch - '0', ch = getchar();
	return s * w;
}
//bool read1(){
//	bool s = 0;
//	char ch = getchar();
//	while(ch >= '0' && ch <= '9') s = s* 10 + ch - '0', ch = getchar();
//	return s;
//}

void add(int from, int to, int w){
	e[++num_edge].to = to;
	e[num_edge].w = w;
	e[num_edge].nxt = head[from];
	head[from] = num_edge;
} 

int find(int x){return fath[x] == x ? x : fath[x] = find(fath[x]); }

void dfs(int x, int fa){
	for(int i = head[x]; i; i = e[i].nxt){
		int v = e[i].to;
		if(v == fa) continue;
		dis[v] = (dis[x] + e[i].w) % mod;
		dfs(v, x), siz[x] += siz[v];
	}
}

void dfs2(int x, int fa){
	for(int i = head[x]; i; i = e[i].nxt){
		int v = e[i].to;
		if(v == fa) continue;
		int jia = ((point - siz[v]) % mod + mod) % mod;
		int jian = siz[v] * e[i].w % mod;
		jia = (jia * e[i].w) % mod;
		f[v] = ((f[x] + jia - jian) % mod + mod) % mod;
		dfs2(v, x); 
	}
}

signed main()
{
	n = read(), m = read();
	bool flag = 0, se = 0;
	se = read();
	if(se) flag = 1, type[1] = se ^ 1;
	else type[1] = 0;
	for(int i = 2; i <= n; ++i){
		type[i] = read();
//		cin>>type[i];
		if(flag) type[i] = (type[i] ^ 1);
		siz[i] = type[i];//顺便处理在以i为根的子树中,与1节点不同的点的个数 
	}
	for(int i = 1; i <= n; ++i) fath[i] = i;
	int x = 2, cnt = 0;
	for(int i = 1, u, v; i <= m; ++i){
		u = read(), v = read();
		int uf = find(u), vf = find(v);
		if(uf != vf){
			fath[uf] = vf;
			add(u, v, x), add(v, u, x);
			//cnt++;
		}
//			if(++cnt == n - 1) break;
		x = (x * 2) % mod;
	}
	dfs(1, 1), point = siz[1];
	for(int i = 1; i <= n; ++i){
		if(type[i]) f[1] = (f[1] + dis[i]) % mod;//先暴力把1与其他点的权值和加起来 
	} 
	dfs2(1, 1);
	int ans = 0;
	for(int i = 1; i <= n; ++i){
		if(!type[i]) ans = (ans + f[i]) % mod;
	}
	printf("%d", ans);
	return 0;
}

posted @ 2020-11-04 16:35  Suzt_ilymtics  阅读(112)  评论(1编辑  收藏  举报