zoukankan      html  css  js  c++  java
  • CH3602 Counting Swaps

    背景

    https://ipsc.ksp.sk/2016/real/problems/c.html

    Just like yesterday (in problem U of the practice session), Bob is busy, so Alice keeps on playing some single-player games and puzzles. In her newest puzzle she has a permutation of numbers from 1 to n. The goal of the puzzle is to sort the permutation using the smallest possible number of swaps.

    Instead of simply solving the puzzle, Alice is wondering about the probability of winning it just by playing at random. In order to answer this question, she needs to know the number of optimal solutions to her puzzle.

    描述

    给定一个 1~n 的排列 p_1,p_2,…,p_n,可进行若干次操作,每次选择两个整数 x,y,交换 p_x,p_y。设把 p_1,p_2,…,p_n 变成单调递增的排列 1,2,…,n 至少需要 m 次交换。求有多少种操作方法可以只用 m 次交换达到上述目标。因为结果可能很大,你只需要输出对 10^9+9 取模之后的值。1≤n≤10^5。
    例如排列 2,3,1 至少需要2次交换才能变为 1,2,3。操作方法共有3种,分别是:
    先交换数字2,3,变成 3,2,1,再交换数字3,1,变成 1,2,3。
    先交换数字2,1,变成 1,3,2,再交换数字3,2,变成 1,2,3。
    先交换数字3,1,变成 2,1,3,再交换数字2,1,变成 1,2,3。

    You are given a permutation p1, …, pn of the numbers 1 through n. In each step you can choose two numbers x < y and swap px with py.

    Let m be the minimum number of such swaps needed to sort the given permutation. Compute the number of different sequences of exactly m swaps that sort the given permutation. Since this number may be large, compute it modulo 109 + 9.

    输入格式

    The first line of the input file contains an integer t specifying the number of test cases. Each test case is preceded by a blank line.

    Each test case consists of two lines. The first line contains the integer n. The second line contains the sequence p1, …, pn: a permutation of 1, …, n.

    In the easy subproblem C11 ≤ n ≤ 10.

    In the hard subproblem C21 ≤ n ≤ 105.

    输出格式

    For each test case, output a single line with a single integer: x mod(10^9+9), where x is the number of ways to sort the given sequence using as few swaps as possible.

    样例输入

    3
    
    3
    2 3 1
    
    4
    2 1 4 3
    
    2
    1 2

    样例输出

    3
    2
    1

    样例解释

    In the first test case, we can sort the permutation in two swaps. We can make the first swap arbitrarily; for each of them, there’s exactly one optimal second swap. For example, one of the three shortest solutions is “swap p1 with p2 and then swap p1 with p3”.

    In the second test case, the optimal solution involves swapping p1 with p2 and swapping p3 with p4. We can do these two swaps in either order.

    The third sequence is already sorted. The optimal number of swaps is 0, and thus the only optimal solution is an empty sequence of swaps.

            </article>
    

    分析

    参照Rose_max的题解。

    对于每个位置i,我们向他应该填的数所在的位置p[i]连一条边
    如此会出来一些环,我们的目的是将这些环拆成n个自环
    对于一个长度为n的环,我们发现要把他拆成n个自环至少需要n-1次操作
    设T(x,y)表示将长度为n的环拆成长度分别为x,y的环的方案数,设f[n]表示将长度为n的环拆成n个自环的方案数
    画图可知
    n为偶数且x=y
    otherwise
    对于长度为x的环的操作全部看成0,长度为y的环的操作全部看成1,进行多重集的排列。可以发现这对应出的就是长度为n的环要拆成n个自环的操作方案
    根据多重集的排列公式有


    最终答案也可以用一个多重集的排列给出
    对于k个长度分别为的环,有

    递推复杂度
    我们把f的前几项求出来找规律可以发现
    如此复杂度降为

    代码

    #include<bits/stdc++.h>
    #define rg register
    #define il inline
    #define co const
    template<class T>il T read(){
        rg T data=0,w=1;
        rg char ch=getchar();
        while(!isdigit(ch)){
            if(ch=='-') w=-1;
            ch=getchar();
        }
        while(isdigit(ch))
            data=data*10+ch-'0',ch=getchar();
        return data*w;
    }
    template<class T>il T read(rg T&x){
        return x=read<T>();
    }
    typedef long long ll;
    
    co int SIZE=1e5+1,mod=1e9+9;
    int p[SIZE],v[SIZE],T,n;
    ll jc[SIZE];
    int power(int a,int b){
    	int c=1;
    	for(;b;b>>=1){
    		if(b&1) c=(ll)c*a%mod;
    		a=(ll)a*a%mod;
    	}
    	return c;
    }
    int main()
    {
    //	freopen(".in","r",stdin),freopen(".out","w",stdout);
    	jc[0]=1;
    	for(int i=1;i<=1e5;++i) jc[i]=jc[i-1]*i%mod;
    	read(T);
    	while(T--){
    		read(n);
    		for(int i=1;i<=n;++i) read(p[i]),v[i]=0;
    		int cnt=0;
    		ll ans=1;
    		for(int i=1;i<=n;++i){
    			if(v[i]) continue;
    			int len=1;
    			v[i]=1;
    			for(int j=p[i];j!=i;j=p[j]) v[j]=1,++len;
    			++cnt;
    			ans=ans*(len==1?1:power(len,len-2))%mod;
    			ans=ans*power(jc[len-1],mod-2)%mod;
    		}
    		ans=ans*jc[n-cnt]%mod;
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    负载均衡器部署方式和工作原理
    Android 有关于* daemon not running.starting it now on port 5037 *ADB
    微信开发常用文档及参考资料
    XML解析之sax解析案例(二)使用sax解析把 xml文档封装成对象
    XML解析之sax解析案例(一)读取contact.xml文件,完整输出文档内容
    XML解析之SAX解析过程代码详解
    通过PHP current()函数获取未知字符键名数组第一个元素的值
    PHP检测链接是否是SSL连接 ,也就是判断HTTPS
    PHP反射ReflectionClass、ReflectionMethod 入门教程
    PHP 反射API说明
  • 原文地址:https://www.cnblogs.com/autoint/p/10466400.html
Copyright © 2011-2022 走看看