CF(441D Valera and Swaps)置换群

题意:1-n的一个排列 p1,?p2,?...,?pn,f(p)的定义是此排列要交换最少的数对可以回到原排列1,2,3,4...n。给一个排列p,要将其变换成f值为m的排列,问至少要交换几个数对,并输出字典序最小的那组答案。

解法:处理出所有的置换群,求出环数k,此时f值为n-k。然后判断n-k和m的大小,分为两种操作

1、加环,这个是在任意元素个数大于1的环内交换任意两个数都可以做到加环

2、减环,交换任意两个环的任意两个元素,就可以做到将两个环连接起来

题目要求是输出字典序最小,那么就暴力搞。

代码:

/******************************************************
* author:xiefubao
*******************************************************/
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <string.h>
//freopen ("in.txt" , "r" , stdin);
using namespace std;

#define eps 1e-8
#define zero(_) (abs(_)<=eps)
const double pi=acos(-1.0);
typedef long long LL;
const int Max=3010;
const int INF=1000000007;

vector<int> vec[Max];
int all=0;
int num[Max];
bool rem[Max];
int m;
int n;
int yinggai;
void make(int t)
{
    if(rem[t])
        return ;
    rem[t]=1;
    vec[all].push_back(t);
    make(num[t]);
}
struct point
{
    int p1,p2;
} points[Max];
bool operator<(point a,point b)
{
    if(a.p1!=b.p1)
        return a.p1<b.p1;
    return a.p2<b.p2;
}
void solve()
{
    all=0;
    memset(rem,0,sizeof rem);
    vec[0].clear();
    for(int i=1; i<=n; i++)
    {
        if(!rem[i])
            make(i),all++,vec[all].clear();
    }
    for(int i=0; i<all; i++)
        sort(vec[i].begin(),vec[i].end());
}
int main()
{
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
        scanf("%d",num+i);
    solve();
    yinggai=n-all;
    //cout<<"  "<<yinggai<<endl;
    scanf("%d",&m);
    cout<<abs(yinggai-m)<<endl;
    if(m>yinggai)
    {
        vector<int> help;
        for(int i=0; i<all; i++)
        {
            if(vec[i][0]!=1)
                help.push_back(vec[i][0]);
        }
        sort(help.begin(),help.end());
        bool b=1;
        printf("1 %d",help[0]);
        for(int i=1; i<m-yinggai; i++)
            printf(" 1 %d",help[i]);
        cout<<endl;
    }
    else  if(m<yinggai)
    {
        int t=yinggai-m;
             //cout<<"fdas";
       for(int i=0;i<t;i++)
       {
           solve();
           pair<int,int > p(Max,Max);
           for(int i=0;i<all;i++)
           {
             if(vec[i].size()>1&&vec[i][0]<p.first)
             {
                 p.first=vec[i][0];
                 p.second=vec[i][1];
             }
           }
           swap(num[p.first],num[p.second]);
           if(i==0)
           printf("%d %d",p.first,p.second);
           else
           printf(" %d %d",p.first,p.second);
       }
    }
    return 0;
}

CF(441D Valera and Swaps)置换群

时间: 2024-08-29 04:34:15

CF(441D Valera and Swaps)置换群的相关文章

Codeforces 441D Valera and Swaps(置换群)

题意: 给定一个1~n的排列(n<=3000),输出字典序最小且次数最少的交换操作,使得操作后的排列可以通过最少m次交换得到排列[1,2,...n] Solution: 可以将排列的对应关系看做边,f[i]=i,代表自环.那么根据置换原理,图中有k个环,则需要最少n-k次交换操作得到排列[1,2...n].所以,先找出图中的环,对同一个环的位置进行标记.这样对不在同一个环的两个位置进行交换,会将两个环合并.将在同一个环内的两个位置进行交换,会将这个环分成两个环. 只需要,判断需要加环还是去环.贪

CF 441E Valera and Number

CF 441E Description 一共执行\(k\)次,每次有\(p\%\)把\(x * 2\),有\((100 - p)\%\)把\(x + 1\).问二进制下\(x\)末尾期望\(0\)的个数. Solution 设\(f[i][j]\)为执行第\(i\)次后\(x + j\)末尾期望\(0\)的个数 加一:$f[i + 1][j - 1] = f[i + 1][j - 1] + (100 - p)% * f[i][j]; $ 乘二:\(f[i + 1][j * 2] = f[i +

Codeforces Round #252 (Div. 2)

A. Valera and Antique Items 题目大意:有一场拍卖,有n个卖家,每个卖家有ki个物品并且底价知道,你想买东西并且只有V元钱,问可以从哪几个商家那里去买 思路:对每个卖家的每样商品作比较即可 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #define maxn 1000 5 using namespace std; 6 int ans[maxn],h,x,k; 7

2017-03-17 Codeforces 441D 置换群,好题 bzoj 4750 思维,按位计算

Codeforces 441D 题意:定义理想序列a[]:对于任意的i有a[i] = i.给出一个1到n的排列p[],可以将排列中的任意两个元素两两交换,定义f(p)为将p变为理想排列的最少交换次数,求将p变成排列q,使得f(q) = m 的最少交换次数和交换方案. tags:才知道置换群,看题解码的.. 使得一个排列有序的最小交换次数 = n - 置换群数目. 置换群,A->B,B->C,C->A,相当于一个轮换.   记住三点: 1.一个大小为L的置换群里面的元素至少且必能互换L-1

CF:Problem 425A - Sereja and Swaps 区间交换最大值

这题比赛的时候不会做,原来是区间暴力. 其实理解起来也觉得挺简单的,可能是看题的时候被交换这个思想束缚了自己的解题吧,所以一直想不出什么好的做法,看了别人的解题茅舍顿开-- 解法:就是在这个数列中先选出一段我们要求的区间,如果在中间取的这段的话,那旁边两段就是剩余的段,也就是我们需要至少k次交换剩余段中最大的值与刚开始选出的段交换最小的值,然后求这选出的这段的和,如此下去更新最大值就得到结果了.选出的段为 [ i , j ],剩余的段就是:[ 0 , i - 1 ] 与 [ j+1 , n -

Old Sorting(转化成单调序列的最小次数,置换群思想)

Old Sorting Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu Submit Status Practice LightOJ 1166 Description Given an array containing a permutation of 1 to n, you have to find the minimum number of swaps to sort the array i

【打CF,学算法——二星级】CodeForces 237B Young Table (构造)

[CF简介] 提交链接:CF 237B 题面: B. Young Table time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output You've got table a, consisting of n rows, numbered from 1 to n. The i-th line of table a contains ci

微信 {&quot;errcode&quot;:40029,&quot;errmsg&quot;:&quot;invalid code, hints: [ req_id: Cf.y.a0389s108 ]&quot;}

{"errcode":40029,"errmsg":"invalid code, hints: [ req_id: Cf.y.a0389s108 ]"} 问题:微信网页授权后,获取到 openid 了,一刷新又没了 微信网页授权获取到的 code 只能使用一次(5分钟内有效),使用一次后,马上失效. 页面授权跳转成功,根据 code 也换取到 openid 了. 此时刷新页面,并不会再次进行授权,而是直接刷新了一下上一次授权跳转后的链接,带的还是

POJ1721_CARDS【置换群】

CARDS Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 1452 Accepted: 776 Description Alice and Bob have a set of N cards labelled with numbers 1 ... N (so that no two cards have the same label) and a shuffle machine. We assume that N is an