T1
今天的第一题是数据结构题,简单来说一下题意。规定:对于任意两个区间(l,r)和(a,b),如果l<a<r或l<b<r,那么区间(a,b)可以到达区间(l,r)。有n次操作,操作有两种:
1、添加一个区间(数据保证添加的区间长度是单调递增的)
2、给定区间编号x,y,询问x能否到y
- 首先很明显的一点,如果区间(a,b)和区间(c,d)可以互相到达,那么两个区间可以合并成一个大区间,具体用并查集维护。
- 由于所给出的区间的长度是递增的,所以对于一个区间(a,b)我们在线段树中对应节点插入它
- 所有包含a或b的那些节点中的区间都可以与当前区间互达
- 对于不可互达的那些区间,他们之间的连通关系可以看成是一个森林(每个子树都有个根,子节点可以走到父节点)
- 找出询问的两个区间的根节点,之后直接判断即可
(代码后续会填坑)
T2
- 第二题是思维难度题。并且数据范围很sb,只有一个n!复杂度的20分和O(n)的复杂度的100分,毒瘤!
- 怎么写啊QAQ
- 看了syq学长的博客,在代码、文字解释的帮助下,终于懂了。
- 首先,置换和排列没啥区间,所以我们不做区分。一个排列是可以看做是有向图,比如当前排列里第i个数是x,就有一条有向边(i,x)。你发现所有的排列构成的有向图一定是由若干个环组成的。
- 然后我们假设已经知道了答案要求的排列,建出了图。当你平方的时候,相当于x到y有一条路,y到z有一条路,然后平方之后是x到z有一条路。那么你发现,这时候平方之后状态的改变与环的奇偶性有关。
- 如果是偶环,那么它会变成两个长度相等的环,两个环中的点是按照原来环的顺序依次一个个取出来的(就是你取一个我取一个这样)。
- 如果是奇环,那么平方之后它仍然是奇环,不过是在图中移两步依次连接。
- 所以知道该怎么做了吧?
- 先把平方的置换p建成图,分出每一个环。如果存在某一个偶环找不到长度相等的环与之合并,就无解。
- 有解的情况如何求出解呢?对于奇环,我们只需要根据刚才说的移两步性质,取答案的时候也移两步就好了。偶环呢?把两个长度相等的偶环左一个右一个地插入合并。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
vector<int>c[N];
int n,cnt,a[N],vis[N],ans[N],id[N];
inline int read(){
char ch=getchar();int num=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){num=num*10+ch-'0';ch=getchar();}
return num*f;
}
void dfs(int x){
c[cnt].push_back(x);
vis[x]=1;
if(!vis[a[x]]) dfs(a[x]);
}
bool cmp(int a,int b){return c[a].size()<c[b].size();}
int main(){
n=read();
for(int i=1;i<=n;++i) a[i]=read();
for(int i=1;i<=n;++i) if(!vis[i]) ++cnt,dfs(i);
for(int i=1;i<=cnt;++i) id[i]=i;
sort(id+1,id+cnt+1,cmp);
for(int i=1;i<=cnt;++i){
//奇环
if(c[id[i]].size()&1){
int mid=c[id[i]].size()>>1;mid++;
for(int j=0;j<c[id[i]].size();++j)
ans[c[id[i]][j]]=c[id[i]][(j+mid)%c[id[i]].size()];
}else{
if(c[id[i+1]].size()!=c[id[i]].size()){
printf("-1\n");
return 0;
}
for(int j=0;j<c[id[i]].size();++j){
ans[c[id[i]][j]]=c[id[i+1]][j];
ans[c[id[i+1]][j]]=c[id[i]][(j+1)%c[id[i]].size()];
}
i++;
}
}
for(int i=1;i<=n;++i) printf("%d ",ans[i]);
return 0;
}
T3
这个不写吧,,,,真不会,很鬼畜的DP。