题目

你需要构造一个排列

初始时\(p_i=i\),一次操作定义为:

  • 选择一些\((x_i,y_i)\),满足每个数字只能出现一次

  • 依次交换\(p_{x_i},p_{y_i}\)

定义一个排列 \(P\) 的最少交换次数为\(f(P)\)

现在 \(P\) 有 \(k\) 个位置的排列顺序是未知的,定义某一种确定顺序的方案是\(P'\)

求\(\sum f(P')\)

\(1 \le n \le 10^6 \ , \ k \le min(12,n)\)

题解

  • 首先操作次数不会超过2,考虑每一个轮换

  • 考虑一个排列\(P\),它的贡献是:

    1.如果所有轮换的大小<=2 ,最少的步数为0/1,贡献为0

    2.如果存在轮换的大小>2,最少的步数为2,考虑贡献

    大小不同的轮换不会互相影响

    大小相同的轮换可以两两拼在一起,也可以单独存在

    写成dp即$h_{i,j} \ = \ h_{i,j-1}i + h_{i,j-2}(j-1)i $

    如果大小为\(i\)的轮换有\(m_i\)个,总贡献为\(\prod h_{i,m_i}\)

  • 如果确定的点指向不确定的点存在一条链\(l\),那么就把不确定的点的大小看做\(|l|+1\)

  • 预处理出所有的\(h\),这样就可以只考虑不确定的点的排列

  • 由于贡献只和轮换的大小有关,可以枚举集合划分再把贡献乘以一个圆排列

  • 时间复杂度\(O(n \ log \ n + bell(k) \ k)\)

Code

  1. #include<bits/stdc++.h>
  2. #define pb push_back
  3. using namespace std;
  4. const int N=1000010,mod=1e9+7;
  5. int n,k,p[N],q[N],cnt[N],pos[N],a[N],b[N],c[N],bl[N],iv[N],vis[N],T,preans,precnt[N],ans,fac[N],prefg1,prefg2,Bell;
  6. vector<int>h[N];
  7. void inc(int&x,int y){x+=y;if(x>=mod)x-=mod;}
  8. int pw(int x,int y){
  9. int re=1;
  10. for(;y;y>>=1,x=1ll*x*x%mod)
  11. if(y&1)re=1ll*re*x%mod;
  12. return re;
  13. }
  14. void pre(){
  15. for(int i=fac[0]=1;i<=n;++i){
  16. fac[i]=1ll*fac[i-1]*i%mod;
  17. int lim=n/i;
  18. h[i].pb(1);h[i].pb(i);
  19. for(int j=2;j<=lim;++j){
  20. h[i].pb((h[i][j-1]+1ll*h[i][j-2]*(j-1)%mod)*i%mod);
  21. }
  22. }
  23. }
  24. void calc(int tot){
  25. static int st[N],tp;
  26. ++T;tp=0;
  27. for(int i=1;i<=tot;++i)b[i]=0,c[i]=0;
  28. for(int i=1;i<=k;++i)b[bl[i]]++,c[bl[i]]+=a[i];
  29. int re=1,fg1=prefg1,fg2=prefg2;
  30. for(int i=1;i<=tot;++i){
  31. re=1ll*re*fac[b[i]-1]%mod;
  32. cnt[c[i]]++;fg1|=c[i]>1;fg2|=c[i]>2;
  33. if(vis[c[i]]!=T)vis[c[i]]=T,st[++tp]=c[i];
  34. }
  35. if(!fg1)re=1;
  36. if(fg2)re=1ll*re*preans%mod;
  37. for(int i=1;i<=tp;++i){
  38. int x=st[i];
  39. if(fg2)re=1ll*re*iv[x]%mod*h[x][cnt[x]]%mod;
  40. cnt[x]=precnt[x];
  41. }
  42. inc(ans,re);
  43. }
  44. void dfs(int x,int y){
  45. if(x==k+1){calc(y);return;}
  46. for(int i=1;i<=y+1;++i){
  47. bl[x]=i;
  48. dfs(x+1,max(i,y));
  49. }
  50. }
  51. int main(){
  52. freopen("determination.in","r",stdin);
  53. freopen("determination.out","w",stdout);
  54. scanf("%d%d",&n,&k);k=0;
  55. for(int i=1;i<=n;++i){
  56. scanf("%d",&p[i]);
  57. if(p[i])q[p[i]]=i;else pos[++k]=i;
  58. }
  59. for(int i=1;i<=k;++i){
  60. int len=1;vis[pos[i]]=1;
  61. for(int j=q[pos[i]];j;j=q[j])vis[j]=1,len++;
  62. a[i]=len;
  63. }
  64. for(int i=1;i<=n;++i)if(!vis[i]){
  65. int len=1;vis[i]=1;
  66. for(int j=p[i];j!=i;j=p[j])vis[j]=1,len++;
  67. cnt[len]++;prefg2|=len>2;prefg1|=len>1;
  68. }
  69. pre();
  70. preans=1;
  71. for(int i=1;i<=n;++i){
  72. precnt[i]=cnt[i];
  73. preans=1ll*preans*h[i][cnt[i]]%mod;
  74. iv[i]=pw(h[i][cnt[i]],mod-2);
  75. vis[i]=0;
  76. }
  77. dfs(1,0);
  78. cout<<ans<<endl;
  79. return 0;
  80. }

【JZOJ100207】【20190705】决心的更多相关文章

  1. 微软的决心,开发者的信心!惊喜的 Connect(); // 2016

    微软的决心,开发者的信心!惊喜的 Connect(); // 2016   Visual Studio for Mac 2014 年 11 月 13 日,微软宣布 .NET 开源与跨平台.两年后的今天 ...

  2. happy and angry day! 2019-07-05

    2019-07-05 01:59:51 现在我是挺开心的哈! 直面困难!迎难而上!毫无畏惧! 现在我的结果,少不了大家给我的支持与鼓励! 鸣谢 章香涛老师---------在各个方面鼓舞了我,激发了我 ...

  3. _00023 Kafka 奇怪的操作_001它们的定义Encoder达到Class数据传输水平和决心

    博文作者:妳那伊抹微笑 博客地址:http://blog.csdn.net/u012185296 博文标题:_00023 Kafka 诡异操作_001自己定义Encoder实现Class级别的数据传送 ...

  4. 谁的用户在世界上是&#160;&#160;明基决心保时捷设计标准

        谈到保时捷.相信非常多人都非常了解,世界名车啊,仅仅有高富帅才玩儿得起.只是,假设由保时捷的设计师来设计一款显示器,水准一流.质地厚道,且价格亲民,你怎么看?     如近期京东上热销的明基G ...

  5. C指针决心 ------ 指针的概念和元素

     本文是自己学习所做笔记,欢迎转载,但请注明出处:http://blog.csdn.net/jesson20121020 指针在C语言中的地位,不用多说. 指针的概念 指针是一个特殊的变量,它里面存储 ...

  6. C指针决心 ------ 指针表达式

    本文是自己学习所做笔记.欢迎转载.但请注明出处:http://blog.csdn.net/jesson20121020 所谓的指针表达式是指一个表达式.其结果是一个指针. 例1. int  a,b; ...

  7. OCP-1Z0-051-标题决心-文章2称号

    2. View the Exhibit to examine the description for the SALES table. Which views can have all DML ope ...

  8. C++ 虚函数表决心

    C++ 虚函数表解析 xml:namespace prefix = o /> 陈皓 http://blog.csdn.net/haoel 前言 C++中的虚函数的作用主要是实现了多态的机制. 关 ...

  9. OCP-1Z0-051-标题决心-文章5称号

    5. Which SQL statements would display the value 1890.55 as $1,890.55? (Choose three .) A. SELECT TO_ ...

随机推荐

  1. 常见框架和WSGI协议

    三大框架对比 Django 大而全 自带的功能特别特别多 类似于航空母舰 有时候过于笨重 Flask 小而精,只保留了核心功能,其他可以自由选择 第三方的模块特别特别多,如果将flask第三方模块全部 ...

  2. RabbitMQ 在Windows环境下安装

    1. 下载RabbitMQ和Erlang RabbitMQ下载地址  https://www.rabbitmq.com/install-windows.html RabbitMQ是用Erlang编程语 ...

  3. Reactor的NIO线程模型

    1.Reactor单线程模型 传统的javaNIO通信的线程模型.该线程模型仅有一个I/O线程处理所有的I/O操作,如下图:   单线程模型的Reactor 所有的客户端都连接到一个I/O线程负责的A ...

  4. moodle3.7上传中文文件,无法引用,图片不显示

    初始安装moodle3.7 上传图片,名称为中文时,无法引用图片,图片不显示.这里采用修改moodle根目录下的config.php文件, 添加了变量$CFG->slasharguments = ...

  5. Java自学-I/O 缓存流

    Java 缓存流BufferedReader,PrintWriter 以介质是硬盘为例,字节流和字符流的弊端: 在每一次读写的时候,都会访问硬盘. 如果读写的频率比较高的时候,其性能表现不佳. 为了解 ...

  6. HighChat动态绑定数据 数据后台绑定(三)

    今天看了几位大佬的博客,学到了一些,现在分享一下,也作为以后的参考 不多说看代码 1.后台代码 public ActionResult Ajax2() { ReportData reportData ...

  7. 【开发工具】- Xshell过期了怎么办?

    点击下边链接下载免费版 http://www.netsarang.com/download/free_license.html

  8. sql server 大数据, 统计分组查询,数据量比较大计算每秒钟执行数据执行次数

    -- 数据量比较大的情况,统计十分钟内每秒钟执行次数 ); -- 开始时间 ); -- 结束时间 declare @num int; -- 结束时间 set @begintime = '2019-08 ...

  9. vue中路由拦截无限循环的情况

    router.beforeEach(async (to, from, next) => { if (token) { if (whiteList.indexOf(to.path) != -1) ...

  10. Java 之 枚举(Enum)

    一.枚举 1.概述 枚举:JDK1.5引入的,类似于穷举,一一罗列出来 Java 枚举:把某个类型的对象,全部列出来 2.应用 什么情况下会用到枚举类型? 当某个类型的对象是固定的,有限的几个,那么就 ...