Codeforces Round #319 (Div. 2) D

E

A tree of size n is an undirected connected graph consisting of n vertices without cycles.

Consider some tree with n vertices. We call a tree invariant relative to permutation p = p1p2... pn, if for any two vertices of the tree u andv the condition holds: "vertices u and v are connected by an edge if and only if vertices pu and pv are connected by an edge".

You are given permutation p of size n. Find some tree size n, invariant relative to the given permutation.

题意说的是给了一个数列p1p2... pn 组成的数是1到n。然后让你构造一棵N个点的树要保证树中 u和v存在路径, 那么在这颗树种pu,和pv也必须存在路径

想法:   如果pv pu 有连线 那么P[pv] P[pu]也要有联系,我们发现这样会是一个循环,这样我们就可以知道,在同一个循环内除了 长度为1 或者2的可以自己和自己连接,其他都必须和1 或者2连接

如果最小的一个循环节大小为1的循环节,那么就有解,你可以让他去连接除了他自己之外的任意一个循环节,这样算算边完全是n-1条

如果最小的一个循环节为2的那么其他的存在循环节的话必须为2的倍数,你可以画一下他们只要不是倍数关系,可定乱套了。

如果最小的一个循环节大于2肯定无解,因为他要和自己连都已经形成环了

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string.h>
#include <vector>
#include <set>
using namespace std;
const int maxn=100005;
struct edg{
  int a,b;
  edg(int ca=0,int cb=0){
    if(ca>cb)swap(ca,cb);
    a=ca; b=cb;
  }
  bool operator == (const edg &rhs)const{
    return a==rhs.a&&b==rhs.b;
  }
  bool operator <(const edg &rhs)const {
    return a<rhs.a||(a==rhs.a&&b<rhs.b);
  }
};
vector<int>G[maxn];
int A[maxn],n;
bool use[maxn];
set<edg>Q;
void bfs(int root, int to)
{
    while(true){
        edg e=edg(root,to);
        if(Q.count(e))return ;
        else Q.insert(e);
        root=A[root];
        to=A[to];
    }
}
void solve1(){
    int root=G[1][0];
    for(int i=1; i<G[1].size(); i++)
    {
        edg a=edg(root,G[1][i]);
        Q.insert(a);
    }
    for(int i=2; i<=n; i++)
    {
        int siz=G[i].size();
        for(int j=0; j<siz; j++)
        {
             int to=G[i][j];
             bfs(root,to);
        }
    }
}
void solve2()
{
    int root1=G[2][0];
    int root2=A[root1];
    edg e=edg(root1,root2);
    Q.insert(e);
    for(int i=1; i<G[2].size(); i++)
        bfs(root1,G[2][i]);
   for(int i=3; i<=n; i++)
    {
        int siz=G[i].size();
        for(int j=0; j<siz; j++)
        {
             int to=G[i][j];
             bfs(root1,to);
        }
    }
}
int main()
{

    scanf("%d",&n);
    for(int i=1; i<=n; i++)
        scanf("%d",&A[i]);
    for(int i=1; i<=n; i++)
    {
        if(use[i])continue;
        int siz=0,L=A[i];
        while(use[L]==false){
             use[L]=true;
            siz++;
            L=A[L];
        }
        G[siz].push_back(i);
    }
    if(G[1].size()==0&&G[2].size()==0){
         puts("NO"); return 0;
    }
    if(G[1].size())solve1();
    else {
        for(int i=2; i<=n; i++)if(G[i].size()){
            if(i%2){
                puts("NO");return 0;
            }
        }
        solve2();
    }
    puts("YES");
    set<edg>::iterator it;
    for(it = Q.begin() ; it!=Q.end(); ++it)
    {
        edg e = *it;
        printf("%d %d\n",e.a,e.b);
    }
    return 0;
}

时间: 2024-11-03 20:56:45

Codeforces Round #319 (Div. 2) D的相关文章

Codeforces Round #319 (Div. 2) C Vasya and Petya&#39;s Game

因为所有整数都能被唯一分解,p1^a1*p2^a2*...*pi^ai,而一次询问的数可以分解为p1^a1k*p2^a2k*...*pi^aik,这次询问会把所有a1>=a1k && a2 >= a2k &&... a3 >= a3k的数从原来的集合中分开.ai表示pi的幂. 那么只有当这个数的素因子的最大幂都被询问过一次,这个数才能确定.因此答案是所有的不大于n的只有一个素因子的数. #include<bits/stdc++.h> using

Codeforces Round 319 # div.1 &amp; 2 解题报告

Div. 2 Multiplication Table (577A) 题意: 给定n行n列的方阵,第i行第j列的数就是i*j,问有多少个格子上的数恰为x. 1<=n<=10^5, 1<=x<=10^9 题解: 送分题…对于每一行,判断是否存在数x即可…也可以枚举x的因子判断是否出现在表内… #include<cstdio>#include<cstring>inlineint read(){int s =0;char c;while((c=getchar())

Codeforces Round #319 (Div. 2) B Modulo Sum

直接O(n*m)的dp也可以直接跑过. 因为上最多跑到m就终止了,因为sum[i]取余数,i = 0,1,2,3...,m,会有m+1种可能,m的余数只有m种必然有两个相同. #include<bits/stdc++.h> using namespace std; const int maxn = 1e3+5; int cnt[maxn]; bool dp[maxn][maxn]; #define Y { puts("YES"); return 0; } int main(

Codeforces Round #319 (Div. 2) E - Points on Plane

题目大意:在一个平面里有n个点,点坐标的值在1-1e6之间,让你给出一个遍历所有点的顺序,要求每个点走一次,且 曼哈顿距离之和小于25*1e8. 思路:想了一会就有了思路,我们可以把1e6的x,y坐标都分成2000份,每份500,然后这样整个平面就被分成 了2000*2000个区域,然后按区域输出点就行了. 1 #include<bits/stdc++.h> 2 using namespace std; 3 int n; 4 vector<int> ans[2005][2005];

codeforces 576c// Points on Plane// Codeforces Round #319(Div. 1)

题意:有n个点,找到一个顺序走遍这n个点,并且曼哈顿距离不超过25e8. 由于给的点坐标都在0-1e6之间.将x轴分成1000*1000,即1000长度为1块.将落在同一块的按y排序,编号为奇的块和偶的块一个升序,一个降序.有3个量值得关注.一是同一块中x的变化量,其实是不超过1000*n1,n1是第1块中点的数量.那么1000*n1+1000*n2......=1000*n<1e9.后两个量是同一块中y的高度差,另一个是本块最后一个和另一块第一个的高度差.这种做法下相邻两块这两个高度差的和是小

Codeforces Round #279 (Div. 2) ABCD

Codeforces Round #279 (Div. 2) 做得我都变绿了! Problems # Name     A Team Olympiad standard input/output 1 s, 256 MB  x2377 B Queue standard input/output 2 s, 256 MB  x1250 C Hacking Cypher standard input/output 1 s, 256 MB  x740 D Chocolate standard input/

Codeforces Round #428 (Div. 2)

Codeforces Round #428 (Div. 2) A    看懂题目意思就知道做了 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i

Codeforces Round #424 (Div. 2) D. Office Keys(dp)

题目链接:Codeforces Round #424 (Div. 2) D. Office Keys 题意: 在一条轴上有n个人,和m个钥匙,门在s位置. 现在每个人走单位距离需要单位时间. 每个钥匙只能被一个人拿. 求全部的人拿到钥匙并且走到门的最短时间. 题解: 显然没有交叉的情况,因为如果交叉的话可能不是最优解. 然后考虑dp[i][j]表示第i个人拿了第j把钥匙,然后 dp[i][j]=max(val(i,j),min(dp[i-1][i-1~j]))   val(i,j)表示第i个人拿

Codeforces Round #424 (Div. 2) C. Jury Marks(乱搞)

题目链接:Codeforces Round #424 (Div. 2) C. Jury Marks 题意: 给你一个有n个数序列,现在让你确定一个x,使得x通过挨着加这个序列的每一个数能出现所有给出的k个数. 问合法的x有多少个.题目保证这k个数完全不同. 题解: 显然,要将这n个数求一下前缀和,并且排一下序,这样,能出现的数就可以表示为x+a,x+b,x+c了. 这里 x+a,x+b,x+c是递增的.这里我把这个序列叫做A序列 然后对于给出的k个数,我们也排一下序,这里我把它叫做B序列,如果我