今天的题…还好…不是特别难qwq…只不过没想到T2竟然是个结论题,手玩玩出来的(可能是我太傻了吧QAQ),结果只拿了10分…还有这个T1…输入竟然是一个n加两个生成数据的
seed …刚看到时,我一脸懵逼…
T1
题意:一个人画出了n个点,从
1∼n 进行标号,并决定使用特殊方法连边。对于第i个点(2≤i≤n) ,他有两种连边方法:
(1):将这个点与1∼i−1号点都连一条边;
(2):不作操作(即不向前连边);
他画了很多图,但他不知道哪一些是“美丽的”。一个图是“美丽的”当且仅当这个图存在完美匹配。所以要你帮助他判断哪些图是“美丽的”。
P.S.:这题的输入文件十分不一样,第一行包含一个正整数T,表示数据组数。
对于第t 组数据,第t+1行有三个整数n,seed,seed2
这三个数将用于生成一段数字p[2...n],p[i]表示第i个点的连边方案。(并给你了个makedata.cpp/pas )…
画外音:看上去这题一脸…不可做的样子…实际上是送分题(雾)。
思路&&题解:这题第一眼看上去要求完美匹配,是一件非常烦的事情。但是,当再看一遍题目就会发现,其实只用O(n)扫一遍就好了qwq。首先,n%2==1时一定是不行的,因为显然完美匹配的顶点必然有偶数个;其次,p[n]一定不能是2,若
p[n]==2 ,则第n个点无法与前面任何一个点进行匹配。知道这两点后,我们可以从后往前扫一遍,用一个num (初始值为0)的变量来完成这个过程。对于每个点i,若p[i]==1 ,则num++;否则,num−−,若num<0,则直接跳出,输出No。否则遍历一遍之后,若num≥0,就是Yes。(当时我用了个数组,来模拟栈…是不是很傻233)
以下是T1的makedata代码:
#include <bits/stdc++.h>
using namespace std;
int p[2000005];
int seed,seed2,n;
int getrand() {
seed=((seed*(12321+n/1000))^9999)%32768;
return seed;
}
int getrand2() {
seed2=((seed2*(12321+n/1000))^9999)%32768;
return seed2;
}
void generateData() {
scanf("%d%d%d",&n,&seed,&seed2);
memset(p,0,sizeof p);
for(int i=2;i<=n;i++)
p[i]=((getrand()/128)%2)^((getrand2()/128)%2);
for(int i=2;i<=n;i++)
p[i]++;
}
int main() {
generateData();
return 0;
}
T2
题意:给你一个从1开始(即数列第一项为
f(1) )的等差数列的两项f(a),f(b),给出c,d,m,现在要求你将集合A={f(c),f(c+1),...,f(d−1),f(d)}拆成m个互不相交的集合,要求这m 个集合元素个数和元素之和均相等。
给出任意一种可行解(每行输出一个集合的元素,并在行末输出一个0)。(数据保证有解)。
思路:这题,我当时搞了两个小时也没想出什么结果(没想到最后是手玩出结论啊啊啊QAQ)…到最后只拿了一个集合的元素个数与
int now=1;
for(int i=1;i<=len;i++) {
myset[now].push_back(seq[i]);
if(i%x!=0)
now=now%x+1;
}
for(int i=1;i<=m;i++) {
for (unsigned j=0;j<myset[i].size();j++) {
printf("%lld ",myset[i][j]);
}
printf("0\n");
}
return 0;
题解:设n=(d−c+1)÷m,问题转化为将1∼(d−c+1)这连续(d−c+1)项填入一个n行
m 列的矩阵,每一列对应一个集合。先将这个数列的前3⋅m项提出不管,后面的(m−3)⋅n项通过元素个数为偶数的情况解决(具体不详细讲了qwq)。
通过手玩(大雾)或记结论我们可以得到这样一种做法:
对于第一行,按照正常的顺序1∼n填写。
对于第二行,将n+1−2⋅n按顺序填写:从右边第一个开始,每填一格空一格,填到尽头时,再从右边第一个空格开始,填满所有的空格。
对于第三行,将2⋅n+1−3⋅n按顺序填写:从右边第二个开始,每填一格空一格,填到尽头时,再从右边第一个空格开始,填满所有的空格。
正确性的话..限于篇幅我就不讲了,有兴趣的同学可以自己证一证(我太懒了qwq)。
T3
题意:给定一个以1为根的有
n 个节点的树,一共有m次询问。每次询问,给出两个点集A,B 。
求解lca(x,y)深度的最大值,其中x∈A,y∈B。
规定1号点的深度为1 。
思路:当时在想这题的时候,我没想出个所以然,于是最后打了个暴力,两重for循环遍历点集A和
题解:假设我们现在处理x点,其他任何点与
x 点的LCA只可能是x或x 的祖先。而根据LCA的不同,这些点可以被分为一些联通块。每一个联通块的内部都是一段连续的dfs序。可以证明,有这样一个结论:
依照dfs序,若两个点的dfs序越接近,则两个点的LCA深度越大。
每次询问将其中一个点集按照dfs序排序,对于另外一个点集中的每个点,其在这个点集中dfs序最近的点。P.S.:有可能是dfs序比它大的,也有可能是比它小的。
时间复杂度为O(nlogn)。