鞍山热身赛的题,也是去年多校原题

题目大意:

求n个数的排列中满足相邻两个数互质的排列的数量并取模

当时的思路就是状压dp.. dp[i][state]  state用二进制记录某个数是否被取走,i 表示当前序列末尾的数字

然后gcd状态转移

可是n是28,算了一下有几亿个状态。。没法做。。

回来之后找了题解发现可以用数学方法优化,于是搞了半天终于ac了

首先在这个问题中:

两个数是否互质只与他们的质因数有关,所以质因数相同的数是等价的,称作此问题的等价类

质因数找到这些等价类,并得到每个类中的数的数量是很容易的。。

所以只需要对这些等价类进行处理,最后对每个等价类再乘以数量的排列数就可以得到答案了。

不过此时有了数量,就不能用二进制状压了,应该采用哈希来状压。

研究了一会发现哈希状压和二进制状压差不多,只不过把基数从(1+1)^n变成了 (num[1]+1)*(num[2]+1)....也是很好理解的

这些状态处理完,发现对于n=28只有 5600000个状态了,等价类数是17 所以复杂度是17*5600000

一交MLE了。由于取模最大30000,把数组改为short,中间结果int防溢出,不爆内存了。

然后时限30s,以为可以过,结果又T了。。

于是又想了一会,发现17,19,23这三个数与其他任意一个数的互质。。所以他们与 1 是等价的

加了这个优化以后复杂度下降到约为 14*1800000

8800ms AC...

代码如下

  1. #include<stdio.h>
  2. #include<string.h>
  3. #include<algorithm>
  4. using namespace std;
  5. const int prime[]={,,,,,,,,};
  6. const int np=;
  7. int state[];
  8. int g[][];
  9. int vi[];
  10. int num[];
  11. int base[];
  12. short dp[][];
  13. bool ok[];
  14. int n,m,ns,st;
  15. void ini()
  16. {
  17. scanf("%d%d",&n,&m);
  18. memset(g,,sizeof(g));
  19. memset(vi,,sizeof(vi));
  20. memset(num,,sizeof(num));
  21. ns=;
  22. state[++ns]=;
  23. num[ns]=;
  24. for(int i=;i<=n;i++)
  25. {
  26. st=;
  27. if(ok[i])
  28. {
  29. num[]++;
  30. continue;
  31. }
  32. for(int j=;j<np;j++)
  33. {
  34. if(i%prime[j]==)
  35. {
  36. st|=(<<j);
  37. }
  38. }
  39. if(!vi[st])
  40. {
  41. state[++ns]=st;
  42. num[ns]=;
  43. vi[st]=ns;
  44. }
  45. else
  46. {
  47. num[vi[st]]++;
  48. }
  49. }
  50. for(int i=;i<=ns;i++)
  51. {
  52. for(int j=;j<=ns;j++)
  53. {
  54. if((state[i]&state[j])==)
  55. g[i][j]=;
  56. }
  57. }
  58. base[]=;
  59. st=;
  60. for(int i=;i<=ns;i++)
  61. {
  62. base[i+]=base[i]*(num[i]+);
  63. st+=base[i]*num[i];
  64. }
  65. }
  66. int getnum(int i,int x)
  67. {
  68. int res=(x%base[i+])/(base[i]);
  69. return res;
  70. }
  71. int getstate(int i,int num)
  72. {
  73. return num*base[i];
  74. }
  75. void dfs(int t,int x)
  76. {
  77. if(t==)
  78. {
  79. dp[x][]=;
  80. return ;
  81. }
  82. if(dp[x][t]!=-)
  83. return;
  84. dp[x][t]=;
  85. for(int i=;i<=ns;i++)
  86. {
  87. if(g[x][i]&&getnum(i,t)>=)
  88. {
  89. dfs(t-base[i],i);
  90. dp[x][t]=((int)dp[x][t]+dp[i][t-base[i]])%m;
  91. }
  92. }
  93. return;
  94. }
  95. int main()
  96. {
  97. #ifndef ONLINE_JUDGE
  98. freopen("in.txt","r",stdin);
  99. #endif // ONLINE_JUDGE
  100. int T;
  101. scanf("%d",&T);
  102. memset(ok,,sizeof(ok));
  103. ok[]=;
  104. ok[]=;
  105. ok[]=;
  106. while(T--)
  107. {
  108. ini();
  109. memset(dp,-,sizeof(dp));
  110. int ans=;
  111. for(int i=;i<=ns;i++)
  112. {
  113. dfs(st-base[i],i);
  114. ans=((int)ans+dp[i][st-base[i]])%m;
  115. }
  116. for(int i=;i<=ns;i++)
  117. {
  118. while(num[i]>)
  119. {
  120. ans=((int)ans*num[i])%m;
  121. num[i]--;
  122. }
  123. }
  124. printf("%d\n",ans);
  125. }
  126. }

hdu4623:crime 数学优化dp的更多相关文章

  1. 【转】斜率优化DP和四边形不等式优化DP整理

    (自己的理解:首先考虑单调队列,不行时考虑斜率,再不行就考虑不等式什么的东西) 当dp的状态转移方程dp[i]的状态i需要从前面(0~i-1)个状态找出最优子决策做转移时 我们常常需要双重循环 (一重 ...

  2. P2120 [ZJOI2007]仓库建设 斜率优化dp

    好题,这题是我理解的第一道斜率优化dp,自然要写一发题解.首先我们要写出普通的表达式,然后先用前缀和优化.然后呢?我们观察发现,x[i]是递增,而我们发现的斜率也是需要是递增的,然后就维护一个单调递增 ...

  3. 【学习笔记】动态规划—斜率优化DP(超详细)

    [学习笔记]动态规划-斜率优化DP(超详细) [前言] 第一次写这么长的文章. 写完后感觉对斜优的理解又加深了一些. 斜优通常与决策单调性同时出现.可以说决策单调性是斜率优化的前提. 斜率优化 \(D ...

  4. 洛谷P2365/5785 任务安排 题解 斜率优化DP

    任务安排1(小数据):https://www.luogu.com.cn/problem/P2365 任务安排2(大数据):https://www.luogu.com.cn/problem/P5785 ...

  5. bzoj-4518 4518: [Sdoi2016]征途(斜率优化dp)

    题目链接: 4518: [Sdoi2016]征途 Description Pine开始了从S地到T地的征途. 从S地到T地的路可以划分成n段,相邻两段路的分界点设有休息站. Pine计划用m天到达T地 ...

  6. bzoj-1096 1096: [ZJOI2007]仓库建设(斜率优化dp)

    题目链接: 1096: [ZJOI2007]仓库建设 Description L公司有N个工厂,由高到底分布在一座山上.如图所示,工厂1在山顶,工厂N在山脚.由于这座山处于高原内陆地区(干燥少雨),L ...

  7. 【Codeforces720D】Slalom 线段树 + 扫描线 (优化DP)

    D. Slalom time limit per test:2 seconds memory limit per test:256 megabytes input:standard input out ...

  8. 单调队列优化DP,多重背包

    单调队列优化DP:http://www.cnblogs.com/ka200812/archive/2012/07/11/2585950.html 单调队列优化多重背包:http://blog.csdn ...

  9. [BZOJ3156]防御准备(斜率优化DP)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3156 分析: 简单的斜率优化DP

随机推荐

  1. JS(六)

    没有视频看了,心里有点慌啊,像这种每天都会灌输很多知识的学习方式,我觉得提前预习真的是有奇效,不然不容易跟上老师的思维. 1.发送验证码:简单 <!DOCTYPE html> <ht ...

  2. apue

    #ifndef apue_h #define apue_h #define _POSIX_C_SOURCE 200809L #if defined(SOLARIS) /* Solaris 10 */ ...

  3. Javascript:getElementsByClassName

    背景: 由于原生的getElementsByClassName不支持在指定标签中查找指定元素为指定class的情况,所以,这里舍弃了原生的方法调用   方法一: function getElement ...

  4. 关闭钩子(shutdown hook)的作用

    DK1.3介绍了java.lang.Runtime class的addShutdownHook()方法.如果你需要在你的程序关闭前采取什么措施,那么关闭钩子(shutdown hook)是很有用的. ...

  5. 浙江大学PAT上机题解析之5-05. QQ帐户的申请与登陆

    实现QQ新帐户申请和老帐户登陆的简化版功能.最大挑战是:据说现在的QQ号码已经有10位数了. 输入格式说明: 输入首先给出一个正整数N(<=105),随后给出N行指令.每行指令的格式为:“命令符 ...

  6. C++ Win32控制台应用程序捕捉关闭事件

      #include#includebool ctrlhandler( DWORD fdwctrltype ){    switch( fdwctrltype )    {    // handle ...

  7. oracle 配置服务端

    oracle 配置服务端,类似我们配置java环境一样 防止乱码的配置: 变量名:NLS_LANG 变量值:SIMPLIFIED CHINESE_CHINA.ZHS16GBK 选择数据库的配置(重要) ...

  8. 读取xml文件信息

    static void Main(string[] args) { XmlTextReader reader = new XmlTextReader(@"D:\zy\visual studi ...

  9. SqlServer跨域查询

    SELECT * FROM OPENDATASOURCE('SQLOLEDB','Data Source=192.168.1.14;User ID=sa;Password=sql.com').eBui ...

  10. 扩展编写jquery插件的方法

    比如要扩展验证功能(jquery.validate.js)中的 messages: { required: "This field is required.", remote: & ...