洛谷P4778 Counting swaps 数论
正解:数论
解题报告:
首先考虑最终的状态是固定的,所以可以知道初始状态的每个数要去哪个地方,就可以考虑给每个数$a$连一条边,指向一个数$b$,表示$a$最后要移至$b$所在的位置
显然每个数只会有一条出边,也只会有一条入边,所以会构成若干条环然后现在的目标就相当于是要通过最少的次数使所有边都变成自环
然后考虑这个交换操作,就相当于是交换两条边的终点
欧克把题目转化完了下面考虑解题
先证明这样一个结论:一个长度为$n$的环要变成$n$个自环至少需要$n-1$步
证明如下:
考虑用数学归纳法
首先长度为2的环要变成2个自环显然是1步
现在考虑若已证明对长度$<k$的环都成立
则对于长度为k的环,显然随意交换两条边的终点后就变成了一个长度为$x$的环和一个长度为$y$的环,且$x+y=k$
那么分别对这两个环都有最少步骤为$(x-1)+(y-1)=k-2$
再加上第一步交换两条边的终点的操作,总的步骤就要$k-2+1=k-1$步
得证(,,,这个证明挺弱智的我$jio$得
接着考虑设$f[x]:$拆长度为$x$的环为$x$个自环的方案数
为了表达方便再设个$g[x][y]$表示长度为$x+y$的环拆成长为$x$的环和长为$y$的环的方案数
首先显然有$g[x][y]=\left\{\begin{matrix}\frac{n}{2}(x=y)\\n(x\neq y)\end{matrix}\right.$
瞎证明下趴,下面为了表达方便提前解释下,交换点对的意思就是交换终点为这两个点的边的终点(,,,有点绕,怪我语文太差$TT$
显然当$x\neq y$的时候
对任意一个点$x$,会有两个点$y_{1}$,$y_{2}$满足交换$\left ( x,y \right )$之后能拆成一个大小为x的环和一个大小为y的环
然后再考虑重复,就每条边会被枚举两次(显然?就两个断点分别作为起点枚举一次嘛$QwQ$,所以就有$g[x][y]=\frac{n\cdot 2}{2}=n$
然后当$x=y$的时候,就显然只有一个点$y$了,所以就是$g[x][y]=\frac{n}{2}$
证毕
然后考虑$f[x]$的递推式?
不难想到$f[x]=\sum_{i=1}^{\frac{x}{2}}g[i][x-i]\cdot f[i]\cdot f[x-i]\cdot \frac{(x-2)!}{(i-1)!\cdot (x-i-1)!}$
再瞎证下$QAQ$
其实前面都不太难get,就枚举拆成的环有多大,然后拆成大小为$i,x-i$的方案数是$g[i][x-i]$,然后内部拆的方案是$f[i]\cdot f[x-i]$
主要大概是要解释下后面这个 $ \frac{(n-2)!}{ (i-1)! \cdot (n-i-1)!} $
就因为两个环是互相独立互不影响的,所以显然可以先做一步第一个环的,再做一步第二个环的,这样子,所以总共有$(n-2)$步就有$(n-2)!$条方案
但考虑到事实上在分别做两个小环的时候就已经考虑到这个问题已经乘过了,所以就再除以一个$(i-1)!\cdot (n-i-1)!$
(一个$upd:$过了一段时间之后重新来看这题发现我是呆呆,,,?这不就是组合数嘛我在想啥???????$/dk/dk/dk$
但是实际上这儿有个优化,,,因为这个复杂度实际上是过不去的,复杂度$O(n^{2})$的,但是可以打表找规律得$f[i]=i^{i-2}$
不会证啊$QAQ$那就不证了趴$QAQ$
最后考虑因为是有若干个环,同样是因为环之间互不影响可以先做一步这个环的再做一步那个环的这样子,所以最后的$ans$就是 $ (\prod_{i=1}^{k} f_{l_i}) \cdot \dfrac{(n-k)!}{\prod_{i=1}^k(l_i-1)!} $
$aya$好像忘记说$l_i$辣,,,,就是说每个环的大小辣
那就做完辣?等下放代码吼$QwQ!$
#include<bits/stdc++.h>
using namespace std;
#define il inline
#define gc getchar()
#define t(i) edge[i].to
#define int long long
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i)
#define e(i,x) for(ri i=head[x];i;i=edge[i].nxt) const int N=1e5+,mod=1e9+;
int head[N],ed_cnt,ln[N],ln_cnt,as,n,jc[N],inv[N];
bool vis[N];
struct ed{int to,nxt;}edge[N<<]; il int read()
{
rc ch=gc;ri x=;rb y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=gc;
return y?x:-x;
}
il int power(ri x,ri y){if(y<)return ;ri ret=;while(y){if(y&)ret=1ll*ret*x%mod;x=1ll*x*x%mod;y>>=;}return ret;}
il void pre()
{
jc[]=;rp(i,,N-)jc[i]=1ll*jc[i-]*i%mod;
inv[N-]=power(jc[N-],mod-);my(i,N-,)inv[i]=1ll*inv[i+]*(i+)%mod;
}
il void ad(ri x,ri y){edge[++ed_cnt]=(ed){x,head[y]};head[y]=ed_cnt;}
int dfs(ri x,ri fa){if(vis[x])return ;vis[x]=;e(i,x)return dfs(t(i),x)+;} signed main()
{
// freopen("4778.in","r",stdin);freopen("4778.out","w",stdout);
int T=read();pre();
while(T--)
{
memset(vis,,sizeof(vis));memset(head,,sizeof(head));ed_cnt=;ln_cnt=;
n=read();rp(i,,n)ad(i,read());rp(i,,n)if(!vis[i])ln[++ln_cnt]=dfs(i,);
as=jc[n-ln_cnt];rp(i,,ln_cnt)as=1ll*as*power(ln[i],ln[i]-)%mod*inv[ln[i]-]%mod;
printf("%lld\n",as);
}
return ;
}
这儿是代码,,,
洛谷P4778 Counting swaps 数论的更多相关文章
- 乘法原理,加法原理,多重集的排列数(多个系列操作穿插的排列数) 进阶指南 洛谷p4778
https://www.luogu.org/problemnew/solution/P4778 非常好的题目,囊括了乘法加法原理和多重集合排列,虽然最后使用一个结论解出来的.. 给定一个n的排列,用最 ...
- 洛谷P4562 [JXOI2018]游戏 数论
正解:数论 解题报告: 传送门! 首先考虑怎么样的数可能出现在t(i)那个位置上?显然是[l,r]中所有无法被表示出来的数(就约数不在[l,r]内的数嘛QwQ 所以可以先把这些数筛出来 具体怎么筛的话 ...
- 洛谷P3104 Counting Friends G 题解
题目 [USACO14MAR]Counting Friends G 题解 这道题我们可以将 \((n+1)\) 个边依次去掉,然后分别判断去掉后是否能满足.注意到一点, \(n\) 个奶牛的朋友之和必 ...
- 洛谷P1134 阶乘问题[数论]
题目描述 也许你早就知道阶乘的含义,N阶乘是由1到N相乘而产生,如: 12! = 1 x 2 x 3 x 4 x 5 x 6 x 7 x 8 x 9 x 10 x 11 x 12 = 479,001, ...
- luogu P4778 Counting swaps
计数套路题?但是我连套路都不会,,, 拿到这道题我一脸蒙彼,,,感谢@poorpool 大佬的博客的指点 先将第\(i\)位上的数字\(p_i\)向\(i\)连无向边,然后构成了一个有若干环组成的无向 ...
- 洛谷P2398 GCD SUM [数论,欧拉筛]
题目传送门 GCD SUM 题目描述 for i=1 to n for j=1 to n sum+=gcd(i,j) 给出n求sum. gcd(x,y)表示x,y的最大公约数. 输入输出格式 输入格式 ...
- 洛谷P2231 [HNOI2002]跳蚤 [数论,容斥原理]
题目传送门 跳蚤 题目描述 Z城市居住着很多只跳蚤.在Z城市周六生活频道有一个娱乐节目.一只跳蚤将被请上一个高空钢丝的正中央.钢丝很长,可以看作是无限长.节目主持人会给该跳蚤发一张卡片.卡片上写有N+ ...
- 洛谷P1414 又是毕业季 [数论]
题目传送门 又是毕业季 题目背景 “叮铃铃铃”,随着高考最后一科结考铃声的敲响,三年青春时光顿时凝固于此刻.毕业的欣喜怎敌那离别的不舍,憧憬着未来仍毋忘逝去的歌.1000多个日夜的欢笑和泪水,全凝聚在 ...
- 洛谷 - P1403 - 约数研究 - 数论
https://www.luogu.org/problemnew/show/P1403 可以直接用线性筛约数个数求出来,但实际上n以内i的倍数的个数为n/i的下整,要求的其实是 $$\sum\limi ...
随机推荐
- 响应式bootstrap - demo
参考资料: bootstrap:http://www.bootcss.com/ 汤姆大叔的博客: <深入理解Bootstrap>http://item.jd.com/11462962.ht ...
- jarvis level6_x64堆溢出unlink拾遗
level6 32位的我没有调出来,貌似32位的堆结构和64位不太一样,嘤嘤嘤?,所以做了一下这个64位的,题目地址,level6_x64 首先看一下程序的结构体 struct list //0x18 ...
- day18正则及re模块
在线测试工具 http://tool.chinaz.com/regex/ 正则表达式本身和python语言没什么联系,只是匹配字符串内容的一种规则:详见:http://www.cnblogs.com/ ...
- 爬虫-requests
一.爬虫系列之第1章-requests模块 爬虫简介 概述 近年来,随着网络应用的逐渐扩展和深入,如何高效的获取网上数据成为了无数公司和个人的追求,在大数据时代,谁掌握了更多的数据,谁就可以获得更高的 ...
- synchronized 是可重入锁吗?为什么?
什么是可重入锁? 关于什么是可重入锁,我们先来看一段维基百科的定义. 若一个程序或子程序可以“在任意时刻被中断然后操作系统调度执行另外一段代码,这段代码又调用了该子程序不会出错”,则称其为可重入(re ...
- figlet
figlet https://aotu.io/notes/2016/11/22/figlet/ 教程 npm i figlet --save-dev var figlet = require('fi ...
- codeforces 502 g The Tree
题解: 一道优秀的题目 有几种做法: 1.维护后缀和 刚开始我想的是维护前缀和 然后用$sum[x]-sum[y]>=dep[x]-dep[y]$来做 但是这样子树赋值为0这个操作就很难进行了 ...
- 使用Redis构建全局并发锁
谈起Redis的用途,小伙伴们都会说使用它作为缓存,目前很多公司都用Redis作为缓存,但是使用Redis仅仅作为缓存未免太大材小用了.深究Redis的原理后你会发现它有很多用途,在很多场景下能够使用 ...
- .net程序员面试小结(内附一些面试题和答案)
今天下午去面试,面试官和HR小姐姐都很好,没有做面试题,用聊天的方式来交流技术,整个过程很轻松,从中也学到了很多知识. 下面就来总结一下面试过程. 一.深刻了解自己的简历 无论是HR还是技术面试人,首 ...
- 浅析uWSGI、uwsgi、wsgi
WSGI协议 首先弄清下面几个概念: WSGI:全称是Web Server Gateway Interface,WSGI不是服务器,python模块,框架,API或者任何软件,只是一种规范,描述web ...