传送门:


http://codeforces.com/problemset/problem/398/E

题解:


首先答案不超过2。

最长环=1时,ans=0

最长环=2时,ans=1

否则,ans=2

考虑有长度大于2的环时如何两步出解。

那么第一步肯定是把大环拆成若干长度不超过2的环。

不妨确定一个x,设它指向y,指向它的是z,那么肯定将y、z交换,这样x、y在一个环里,然后剩下一个len-2的环,不过因为z不能再动了,所以对这个环的拆分就唯一了,一直下去可以把环拆开,并且只考虑这个环的方案数是len。

有多个环时,这些环的选择时可以相交的。

现在有两个环,

一定有一步交换位于不同环上的两个点,如果依然想拆成若干长度不超过2的环,那么剩下的交换也是唯一的。

由于对称问题,也只有len种。

显然两个环的时候必须长度相等才有解。

然后我并不会证更多环没有解。

然后就可以设个\(f[i][j]\)表示长度为i的有j个环的方案数

\(f[i][j]=f[i][j-1]*i+f[i][j-2]*(j-1)*i\),复杂度是调和级数

那么接下来\(O(k!)\)暴力的话也TLE了。

考虑确定每个点就是把若干条链拼起来,那么就只用集合划分了。

Code:


  1. #include<bits/stdc++.h>
  2. #define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
  3. #define ff(i, x, y) for(int i = x, B = y; i < B; i ++)
  4. #define fd(i, x, y) for(int i = x, B = y; i >= B; i --)
  5. #define ll long long
  6. #define pp printf
  7. #define hh pp("\n")
  8. using namespace std;
  9. const int mo = 1e9 + 7;
  10. ll ksm(ll x, ll y) {
  11. ll s = 1;
  12. for(; y; y /= 2, x = x * x % mo)
  13. if(y & 1) s = s * x % mo;
  14. return s;
  15. }
  16. const int N = 1e6 + 5;
  17. int n, k, a[N], r[N], q[N];
  18. ll fac[15];
  19. vector<ll> f[N], nf[N];
  20. int b[N], b0, cnt[N];
  21. int c[N], c0, d[N];
  22. ll ans, sum, s2;
  23. void dg(int x) {
  24. if(x > b0) {
  25. ll s = sum, s3 = s2;
  26. fo(i, 1, c0) {
  27. s3 += c[i] > 2;
  28. s = s * nf[c[i]][cnt[c[i]]] % mo;
  29. cnt[c[i]] ++;
  30. s = s * f[c[i]][cnt[c[i]]] % mo;
  31. }
  32. ll xs = 1;
  33. fo(i, 1, c0) xs = xs * fac[d[i] - 1] % mo;
  34. ans = (ans + (s3 ? s : 1) * xs) % mo;
  35. fo(i, 1, c0) cnt[c[i]] --;
  36. return;
  37. }
  38. fo(i, 1, c0) {
  39. c[i] += b[x];
  40. d[i] ++;
  41. dg(x + 1);
  42. d[i] --;
  43. c[i] -= b[x];
  44. }
  45. c[++ c0] = b[x]; d[c0] = 1;
  46. dg(x + 1);
  47. d[c0] = 0; c0 --;
  48. }
  49. int main() {
  50. freopen("determination.in", "r", stdin);
  51. freopen("determination.out", "w", stdout);
  52. fac[0] = 1; fo(i, 1, 15) fac[i] = fac[i - 1] * i % mo;
  53. scanf("%d %d", &n, &k);
  54. fo(i, 1, n) scanf("%d", &a[i]), r[a[i]] ++;
  55. fo(i, 1, n) {
  56. f[i].resize(n / i + 1);
  57. nf[i].resize(n / i + 1);
  58. f[i][0] = 1;
  59. fo(j, 1, n / i) {
  60. f[i][j] = f[i][j - 1];
  61. if(j >= 2) f[i][j] = (f[i][j] + f[i][j - 2] * (j - 1)) % mo;
  62. f[i][j] = f[i][j] * i % mo;
  63. }
  64. ll s = 1;
  65. fo(j, 1, n / i) s = s * f[i][j] % mo;
  66. s = ksm(s, mo - 2);
  67. fd(j, n / i, 0) nf[i][j] = s, s = s * f[i][j] % mo;
  68. s = 1;
  69. fo(j, 1, n / i) {
  70. nf[i][j] = nf[i][j] * s % mo;
  71. s = s * f[i][j] % mo;
  72. }
  73. }
  74. fo(i, 1, n) if(!r[i]) {
  75. int x = i; q[x] = 1;
  76. b[++ b0] = 0;
  77. do {
  78. b[b0] ++;
  79. x = a[x];
  80. q[x] = 1;
  81. } while(x != 0);
  82. }
  83. fo(i, 1, n) if(!q[i]) {
  84. int x = i, len = 0;
  85. do {
  86. len ++;
  87. x = a[x];
  88. q[x] = 1;
  89. } while(x != i);
  90. cnt[len] ++;
  91. }
  92. sum = 1;
  93. fo(i, 1, n) sum = sum * f[i][cnt[i]] % mo, s2 += cnt[i] * (i > 2);
  94. dg(1);
  95. pp("%lld", ans);
  96. }

CF 398 E(动态规划)的更多相关文章

  1. CF 848E(动态规划+分治NTT)

    传送门: http://codeforces.com/problemset/problem/848/E 题解: 假设0-n一定有一条边,我们得到了一个方案,那么显然是可以旋转得到其他方案的. 记最大的 ...

  2. 四角递推(CF Working out,动态规划递推)

    题目:假如有A,B两个人,在一个m*n的矩阵,然后A在(1,1),B在(m,1),A要走到(m,n),B要走到(1,n),两人走的过程中可以捡起格子上的数字,而且两人速度不一样,可以同时到一个点(哪怕 ...

  3. CF 1096D Easy Problem [动态规划]

    题目链接:http://codeforces.com/problemset/problem/1096/D 题意: 有一长度为n的字符串,每一字符都有一个权值,要求现在从中取出若干个字符,使得字符串中没 ...

  4. CF思维联系–CodeForces - 225C. Barcode(二路动态规划)

    ACM思维题训练集合 Desciption You've got an n × m pixel picture. Each pixel can be white or black. Your task ...

  5. CF 494 F. Abbreviation(动态规划)

    题目链接:[http://codeforces.com/contest/1003/problem/F] 题意:给出一个n字符串,这些字符串按顺序组成一个文本,字符串之间用空格隔开,文本的大小是字母+空 ...

  6. CF 414B Mashmokh and ACM 动态规划

    题意: 给你两个数n和k.求满足以下条件的数列有多少个. 这个数列的长度是k: b[1], b[2], ……, b[k]. 并且 b[1] <= b[2] <= …… <= b[k] ...

  7. CF思维联系– Codeforces-987C - Three displays ( 动态规划)

    ACM思维题训练集合 It is the middle of 2018 and Maria Stepanovna, who lives outside Krasnokamensk (a town in ...

  8. 【DP专辑】ACM动态规划总结

    转载请注明出处,谢谢.   http://blog.csdn.net/cc_again?viewmode=list          ----------  Accagain  2014年5月15日 ...

  9. 【CF932G】Palindrome Partition(回文树,动态规划)

    [CF932G]Palindrome Partition(回文树,动态规划) 题面 CF 翻译: 给定一个串,把串分为偶数段 假设分为了\(s1,s2,s3....sk\) 求,满足\(s_1=s_k ...

随机推荐

  1. JAVA二分插入排序

  2. java输入一个整数N,打印1~n位数

    举个栗子:输入 3 : 打印1,2,3......999 这里要注意一个坑,不可以直接算出最大的数,然后从1开始打印 .因为当n足够大时,n位数必定会超出int范围和long范围 所以我们需要用字符串 ...

  3. Failed to bind properties under '' to com.zaxxer.hikari.Hikari DataSource Spring Boot解决方案

    Description: Failed to bind properties under '' to com.zaxxer.hikari.HikariDataSource: Property: dri ...

  4. web自动化框架抽取示例【Java+selenium】

    web自动化测试框架抽取示例 例子:测试登录模块,对登录的账号和密码进行不同的case校验. 1.1.1 无优化代码login_1 package com.lee.auto.testFrome; im ...

  5. Shiro学习(23)多项目集中权限管理

    在做一些企业内部项目时或一些互联网后台时:可能会涉及到集中权限管理,统一进行多项目的权限管理:另外也需要统一的会话管理,即实现单点身份认证和授权控制. 学习本章之前,请务必先学习<第十章 会话管 ...

  6. Apache中配置数据库连接池(数据源)

    由于基于HTTP协议的Web程序是无状态的,因此,在应用程序中使用JDBC时,每次处理客户端请求都会重新建立数据库链接,如果客户端的请求频繁的话,这将会消耗非常多的资源,因此,在Tomcat中提供了数 ...

  7. MySql命令行无法显示中文

    好烦遇到了,遇到MySql命令行无法显示中文问题????? show variables like 'char%';//显示字符集 set names utf8;//设置字符集 describer t ...

  8. Python中使用item()方法遍历字典的例子

    Python中使用item()方法遍历字典的例子 这篇文章主要介绍了Python中使用item()方法遍历字典的例子,for...in这种是Python中最常用的遍历字典的方法了,需要的朋友可以参考下 ...

  9. PAT_A1130#Infix Expression

    Source: PAT A1130 Infix Expression (25 分) Description: Given a syntax tree (binary), you are suppose ...

  10. Java传输对象模式

    当我们想要在客户端到服务器的一个传递具有多个属性的数据时,可使用传输对象模式.传输对象也称为值对象.传输对象是一个具有getter/setter方法的简单POJO类,并且是可序列化的,因此可以通过网络 ...