6.13 考试总结

因为今天并没有修改,所以只能总结了

又莫名其妙rank1了,貌似是因为我第三题的暴力写的吼?

第一题

貌似是BZOJ原题,zcg他们都做过

但是我没有做过,想了想发现是丝薄的二元关系最小割

按照pty论文里的建图方法弄了一下,算了算K值之后发现要求这个图必须是二分图才可以

然后思考了一下,随机了半个小时的数据跑发现都是二分图(这是OI的证明方法

(我猜这个题目的某种特别的性质决定了这是二分图,没错,就是这样)

于是就放心的写了个二分图染色建图跑最小割QAQ A掉了QAQ

至于二分图的数学证明,是这样的:

1、(a,b)=1,所以a,b不都是偶数

2、考虑a,b都是奇数,不妨设a=2*x-1,b=2*y-1

则(2*x-1)^2+(2*y-1)^2=2*(2*x^2-2*x+2*y^2-2*y+1)

不难发现后面的式子2的指数为1,所以不可能是完全平方数

由于偶数之间不会建边,奇数之间不会建边,所以原图是二分图

不用二分图染色直接分奇偶就可以了

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
using namespace std;

typedef long long LL;
const int maxn=1010;
const int oo=0x7fffffff;
int n,ans,S,T;
int a[maxn],b[maxn];
int h[maxn],cnt=1;
int cur[maxn],col[maxn],vis[maxn];
bool check[maxn][maxn];
struct edge{
	int to,next,w;
}G[5000010];
queue<int>Q;

int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
void add(int x,int y,int z=0){
	++cnt;G[cnt].to=y;G[cnt].next=h[x];G[cnt].w=z;h[x]=cnt;
}
void read(int &num){
	num=0;char ch=getchar();
	while(ch<‘!‘)ch=getchar();
	while(ch>=‘0‘&&ch<=‘9‘)num=num*10+ch-‘0‘,ch=getchar();
}
bool judge(int a,int b){
	int c=gcd(a,b);
	if(c!=1)return false;
	LL now=1LL*a*a+1LL*b*b;
	int k=(int)(sqrt(now));
	if(1LL*k*k!=now)return false;
	return true;
}
void Get_check(){
	for(int i=1;i<=n;++i){
		for(int j=i+1;j<=n;++j){
			if(judge(a[i],a[j])){
				check[i][j]=true;
			}
		}
	}return;
}
void paint(int u){
	for(int i=h[u];i;i=G[i].next){
		int v=G[i].to;
		if(col[v])continue;
		col[v]=3-col[u];
		paint(v);
	}return;
}
void Get_paint(){
	for(int i=1;i<=n;++i){
		for(int j=i+1;j<=n;++j){
			if(check[i][j])add(i,j),add(j,i);
		}
	}
	for(int i=1;i<=n;++i){
		if(!col[i])col[i]=1,paint(i);
	}
}
void build_Graph(){
	memset(h,0,sizeof(h));cnt=1;
	S=0;T=n+1;
	for(int i=1;i<=n;++i){
		for(int j=i+1;j<=n;++j){
			if(check[i][j]){
				int u=i,v=j;
				if(col[u]!=1)swap(u,v);
				add(u,v,oo);add(v,u,0);
			}
		}
	}
	for(int i=1;i<=n;++i){
		if(col[i]==1)add(S,i,b[i]),add(i,S,0);
		else add(i,T,b[i]),add(T,i,0);
	}return;
}
bool BFS(){
	Q.push(S);
	for(int i=S;i<=T;++i)vis[i]=-1;
	vis[S]=0;
	while(!Q.empty()){
		int u=Q.front();Q.pop();
		for(int i=h[u];i;i=G[i].next){
			int v=G[i].to;
			if(vis[v]==-1&&G[i].w>0){
				vis[v]=vis[u]+1;
				Q.push(v);
			}
		}
	}return vis[T]!=-1;
}
int DFS(int x,int f){
	if(x==T||f==0)return f;
	int w,used=0;
	for(int i=cur[x];i;i=G[i].next){
		if(vis[G[i].to]==vis[x]+1){
			w=f-used;
			w=DFS(G[i].to,min(w,G[i].w));
			G[i].w-=w;G[i^1].w+=w;
			if(G[i].w>0)cur[x]=i;
			used+=w;if(used==f)return used;
		}
	}
	if(!used)vis[x]=-1;
	return used;
}
void dinic(){
	while(BFS()){
		for(int i=S;i<=T;++i)cur[i]=h[i];
		ans-=DFS(S,oo);
	}return;
}

int main(){
	freopen("number.in","r",stdin);
	freopen("number.out","w",stdout);
	read(n);
	for(int i=1;i<=n;++i)read(a[i]);
	for(int i=1;i<=n;++i)read(b[i]),ans+=b[i];
	Get_check();Get_paint();
	build_Graph();dinic();
	printf("%d\n",ans);
	return 0;
}

第二题

第二题给了一堆莫名的集合交并的式子

由于这个题目的时间复杂度由读入的点数决定,不难想到虚树一类的东西

考虑如何用树来描述这样的一个关系

当A集合的大小均为1的时候不难发现给定的每个点就是他的父亲

集合的元素就是他到根的所有的点的代表元素

考虑A集合的大小>1,不难发现每个点的父亲是A集合所有点在树上的LCA(即所有点的交

建出树之后我们考虑如何求一些集合的交,考试的时候思考了很久要不要写虚树

开始写之后发现这是求链交的裸模型,然后由于每条链的一个端点是根,所以我们直接将读入的点按DFS序排序

这样答案就是所有点的深度之和减去所有相邻两个点的LCA的深度和(实际上这差不多也就是个虚树的过程

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
using namespace std;

const int maxn=200010;
int n,k,x,N,m;
int anc[maxn][20];
int dep[maxn];
int h[maxn],cnt=0;
struct edge{
	int to,next;
}G[maxn<<1];
int st[maxn],ed[maxn],tot=0;
int S[maxn];

bool cmp(const int &a,const int &b){
	return st[a]<st[b];
}
void add(int x,int y){
	++cnt;G[cnt].to=y;G[cnt].next=h[x];h[x]=cnt;
}
void read(int &num){
	num=0;char ch=getchar();
	while(ch<‘!‘)ch=getchar();
	while(ch>=‘0‘&&ch<=‘9‘)num=num*10+ch-‘0‘,ch=getchar();
}
int LCA(int p,int q){
	if(dep[p]<dep[q])swap(p,q);
	int log;
	for(log=0;(1<<log)<=dep[p];++log);--log;
	for(int i=log;i>=0;--i){
		if(dep[p]-(1<<i)>=dep[q])p=anc[p][i];
	}
	if(p==q)return p;
	for(int i=log;i>=0;--i){
		if(anc[p][i]!=-1&&anc[q][i]!=anc[p][i]){
			p=anc[p][i];q=anc[q][i];
		}
	}return anc[p][0];
}
void merge(int u,int f){
	anc[u][0]=f;dep[u]=dep[f]+1;
	add(f,u);
	for(int i=1;(1<<i)<=N;++i)anc[u][i]=-1;
	for(int i=1;(1<<i)<=N;++i){
		if(anc[u][i-1]!=-1){
			int a=anc[u][i-1];
			anc[u][i]=anc[a][i-1];
		}else break;
	}return;
}
void Get_DFS(int u){
	st[u]=++tot;
	for(int i=h[u];i;i=G[i].next)Get_DFS(G[i].to);
	ed[u]=tot;
}
int main(){
	freopen("legend.in","r",stdin);
	freopen("legend.out","w",stdout);
	read(n);N=n+1;
	for(int i=0;(1<<i)<=N;++i)anc[0][i]=-1;
	for(int i=1;i<=n;++i){
		read(k);
		if(!k){merge(i,0);continue;}
		read(x);int now=x;
		for(int j=2;j<=k;++j){read(x);now=LCA(now,x);}
		merge(i,now);
	}Get_DFS(0);read(m);
	while(m--){
		read(k);
		for(int i=1;i<=k;++i)read(S[i]);
		sort(S+1,S+k+1,cmp);
		int ans=dep[S[1]];
		for(int i=2;i<=k;++i){
			ans+=dep[S[i]];
			int now=LCA(S[i],S[i-1]);
			ans-=dep[now];
		}printf("%d\n",ans);
	}return 0;
}

第三题

代码貌似能7k+

感觉并不想写

就简单口胡一下题解吧

首先考虑只有第一个限制的情况,这是非常简单的

我们建出后缀树,之后做一遍DFS,启发式合并所有的后缀

当前节点是否合法当且仅当相邻的两个后缀的差值的最大值不能超过当前节点的长度

之后我们考虑第二个限制,我们考虑当前这个节点第一次出现的位置

不难发现我们要求的是这个第一次出现的位置在拼接一个后缀后是否是一个后缀

这个我想的做法是在反着建一遍后缀自动机,在启发式合并的时候顺便维护一下

问题就转化成了 简单的最近公共祖先 了QAQ 好开心

没错,如果一个题你要建两个SAM,还要写Spaly启发式合并,然后还要写树链剖分的话

我觉得应该没有什么必要去写了QAQ

时间: 2024-10-07 10:26:44

6.13 考试总结的相关文章

2016.6.13 考试总结

一.哲哲回家 [题目描述]: 哲哲放学了,准备坐公交车回家.因为急着回家看MSN战士,所以他想用最短的时间回家,但是因为学校离家里比较远,有时候他需要转几趟车才可以回家.等车是需要一段时间的,而且每辆公交车的速度不一样,哲哲晕掉了,不知道怎样才可以在最短的时间里回家,作为一名cjoier,你应该帮帮他. 现在一直哲哲所在的城市有N个公交站点(学校在一号站点,哲哲家在N号站点)和M条公交线路,每条公交线路是一个有序集合,公交线路i包含Pi个站点a[i,1],a[i,2]…a[i,Pi],表示i号公

5.13考试整理 x

5.13五一清北基础班试题 1.洛谷P1149 火柴棒等式(时空限制1s / 128MB) 题目描述 给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?等式中的A.B.C是用火柴棍拼出的整数(若该数非零,则最高位不能是0).用火柴棍拼数字0-9的拼法如图所示: 注意: 1.加号与等号各自需要两根火柴棍 2.如果A≠B,则A+B=C与B+A=C视为不同的等式(A.B.C>=0) 3.n根火柴棍必须全部用上 输入输出格式 输入格式: 输入文件matches.in共一行,又一个整数n(n<=

2017/8/13 考试吐槽

2017 8 13 得分:160 联考最后一天--因为不会对拍日常爆炸-- A.最长上升子串 题意:给出一个序列,允许修改一次元素,求出这个序列最长子串. 这个玩意我刚开始以为是个线性$DP$,然后--细节巨多,写出来之后出一个数据卡一个-- 慌得我直喝水直上厕所--然后转到第$8$趟的时候,由于厕所比我在的那个窝风角落凉快,我的脑子算是冷静了下来,仔细一想,卧槽这不是$DP$!我可以先正序求出以每个元素开头子串长度,再倒序求出每个元素结尾子串长度,之后枚举修改位置,检查修改效果!$mdzz$-

5.13考试

5.13五一清北基础班试题 1.洛谷P1149 火柴棒等式(时空限制1s / 128MB) 题目描述 给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?等式中的A.B.C是用火柴棍拼出的整数(若该数非零,则最高位不能是0).用火柴棍拼数字0-9的拼法如图所示: 注意: 1.加号与等号各自需要两根火柴棍 2.如果A≠B,则A+B=C与B+A=C视为不同的等式(A.B.C>=0) 3.n根火柴棍必须全部用上 输入输出格式 输入格式: 输入文件matches.in共一行,又一个整数n(n<=

18.8.13 考试总结

1.1 问题描述请构造一颗n 个节点的树,使得其价值最大.f(d) 表示树上,度数为d 的一个点能够获取的价值.这棵树的价值为Σni=1 f(di)di 表示第i 个点的度数1.2 输入第一行一个整数T,接下来T 组数据,每组数据输入两行.第一行输入整数n.第二行输入n ?? 1 个整数f(i) 代表f(1) f(n ?? 1).1.3 输出对于每组数据输出一行,为能够构造的树的最大价值. 一开始我以为是一道树形dp... 考完了才知道原来这个是一道背包问题 n个节点 总共有2n - 2个度数

总结2017.3.13考试

1.本题考查List接口与实现类的关系.Java的List接口有3个实现类,分别是ArrayList.LinkedList.Vector,它们用于存放多个元素,维护元素的次序,而且允许元素重复.本题应选择D. 4.本题考查HashMap集合类的特性.Java的HashMap 类是一个散列表,它存储的内容是键值对(key-value)映射.HashMap 继承于AbstractMap,实现了Map.Cloneable.java.io.Serializable接口.因为它属于Map接口的类,所以实现

10.13考试总结

1.送分题,\(O(n)\)处理前后缀,枚举断点,或者\(nlogn\)线段树暴力即可 2.根据\(a_i \times k \equiv x\pmod{n}\),导出\(gcd(a_i,n)|x\),我们枚举d|n,如果\(gcd(a_i,n)|d,那么所有的满足gcd(x,n)=d,的x都能被走到\) 因为,d为x的约数,\(gcd(a_i,n)\)为d的约数,所以\(gcd(a_i,n)|x\). 原文地址:https://www.cnblogs.com/ARTlover/p/978440

python 各模块

01 关于本书 02 代码约定 03 关于例子 04 如何联系我们 1 核心模块 11 介绍 111 内建函数和异常 112 操作系统接口模块 113 类型支持模块 114 正则表达式 115 语言支持模块 12 _ _builtin_ _ 模块 121 使用元组或字典中的参数调用函数 1211 Example 1-1 使用 apply 函数 1212 Example 1-2 使用 apply 函数传递关键字参数 1213 Example 1-3 使用 apply 函数调用基类的构造函数 122

转:Python标准库(非常经典的各种模块介绍)

Python Standard Library 翻译: Python 江湖群 10/06/07 20:10:08 编译 0.1. 关于本书 0.2. 代码约定 0.3. 关于例子 0.4. 如何联系我们 核心模块 1.1. 介绍 1.2. _ _builtin_ _ 模块 1.3. exceptions 模块 1.4. os 模块 1.5. os.path 模块 1.6. stat 模块 1.7. string 模块 1.8. re 模块 1.9. math 模块 1.10. cmath 模块