2017.8.15 总结

来源:互联网 发布:python 异或运算符 编辑:程序博客网 时间:2024/05/16 06:30

今天的题…还好…不是特别难qwq…只不过没想到T2竟然是个结论题,手玩玩出来的(可能是我太傻了吧QAQ),结果只拿了10分…还有这个T1…输入竟然是一个n加两个生成数据的seed…刚看到时,我一脸懵逼…

T1

题意:一个人画出了n个点,从1n进行标号,并决定使用特殊方法连边。对于第i个点(2in),他有两种连边方法:
(1)将这个点与1i1号点都连一条边;
(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。否则遍历一遍之后,若num0,就是Yes。(当时我用了个数组,来模拟栈…是不是很傻233)

以下是T1makedata代码:

#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(d1),f(d)}拆成m个互不相交的集合,要求这m个集合元素个数和元素之和均相等。
给出任意一种可行解(每行输出一个集合的元素,并在行末输出一个0)。(数据保证有解)。

思路:这题,我当时搞了两个小时也没想出什么结果(没想到最后是手玩出结论啊啊啊QAQ)…到最后只拿了一个集合的元素个数与m相等的10分…我是先求出整个f(c),f(c+1),...,f(d1),f(d)的序列,然后按如下代码乱搞…(P.S.myset其实是vector,然后seq等都是事先求好的)。

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=(dc+1)÷m,问题转化为将1(dc+1)这连续(dc+1)项填入一个nm列的矩阵,每一列对应一个集合。先将这个数列的前3m项提出不管,后面的(m3)n项通过元素个数为偶数的情况解决(具体不详细讲了qwq)。
通过手玩(大雾)或记结论我们可以得到这样一种做法:
对于第一行,按照正常的顺序1n填写。
对于第二行,将n+12n按顺序填写:从右边第一个开始,每填一格空一格,填到尽头时,再从右边第一个空格开始,填满所有的空格。
对于第三行,将2n+13n按顺序填写:从右边第二个开始,每填一格空一格,填到尽头时,再从右边第一个空格开始,填满所有的空格。
正确性的话..限于篇幅我就不讲了,有兴趣的同学可以自己证一证(我太懒了qwq)。

T3

题意:给定一个以1为根的有n个节点的树,一共有m次询问。每次询问,给出两个点集A,B
求解lca(x,y)深度的最大值,其中xA,yB
规定1号点的深度为1

思路:当时在想这题的时候,我没想出个所以然,于是最后打了个暴力,两重for循环遍历点集AB中的点,每次倍增求个LCA,然后与现在记录的最大深度maxdep比较,若更大则更新maxdep。我在其中加了个剪枝,即:当前扫到的节点x,如果dep[x]maxdep,则直接continue,因为如果原来节点深度小于maxdep,那它的LCA的深度绝对不会大于maxdep。通过爆搜+剪枝我拿了70…qwq。

题解:假设我们现在处理x点,其他任何点与x点的LCA只可能是xx的祖先。而根据LCA的不同,这些点可以被分为一些联通块。每一个联通块的内部都是一段连续的dfs序。可以证明,有这样一个结论:
依照dfs序,若两个点的dfs序越接近,则两个点的LCA深度越大。
每次询问将其中一个点集按照dfs序排序,对于另外一个点集中的每个点,其在这个点集中dfs序最近的点。P.S.有可能是dfs序比它大的,也有可能是比它小的。
时间复杂度为O(nlogn)