题目描述

\(SSY\) 是班集体育委员,总喜欢把班级同学排成各种奇怪的队形,现在班级里有 \(N\) 个身高互不相同的同学,请你求出这 \(N\) 个人的所有排列中任意两个相邻同学的身高差均不为给定整数M的倍数的排列总数。

输入格式

共三行:

第一行为 \(N\)

第二行为 \(N\) 个不同的整数

第三行为 \(M\)

输出格式

一行,为符合条件的排列总数(答案对 \(1234567891\) 取余数)。

样例

样例输入1

3

-1 0 1

2

样例输出1

2

样例输入2

4

1 2 3 4

3

样例输出2

12

数据范围与提示

\(20\%\) 的数据:\(N<=11\)

\(70\%\) 的数据:\(N<=15\)

\(100\%\) 的数据:\(N<=30,M<=1000\)。

分析

对于一个数,它原来的值和它对 \(m\) 取模之后的值在这道题中意义是相同的

所以一共只会有 \(m\) 种数

我们记录一下每一种数有多少个,然后把个数存进栈里

我们会发现,方案数仅与当前的数和剩下个数为 \(x\) 的数有几种有关

比如当 \(m=5\) 时,\(3\ 2\ 2\)和 \(3\ 1\ 1\) 的结果是完全一样的

可以设 \(f[i][j][k][...]\) 为当前选的是第 \(i\) 种数,剩下个数为 \(1\) 的数有 \(j\) 种,剩下个数为 \(2\) 的数有 \(k\) 种 ... 的方案数

数组开不下,所以我们可以用哈希的思想把状态压成一个

对于递归的每一层,开一个 \(map\) 记录一下即可

要注意的是最后要乘上每一种数个数的阶乘,因为同一种数可以任意交换位置

代码

  1. #include<cstdio>
  2. #include<map>
  3. #include<algorithm>
  4. #include<cstring>
  5. #include<cmath>
  6. #define rg register
  7. inline int read(){
  8. rg int x=0,fh=1;
  9. rg char ch=getchar();
  10. while(ch<'0' || ch>'9'){
  11. if(ch=='-') fh=-1;
  12. ch=getchar();
  13. }
  14. while(ch>='0' && ch<='9'){
  15. x=(x<<1)+(x<<3)+(ch^48);
  16. ch=getchar();
  17. }\
  18. return x*fh;
  19. }
  20. #define ull unsigned long long
  21. const int maxn=35;
  22. const int mod=1234567891;
  23. const ull bas=233333;
  24. int a[maxn],sta[maxn],b[maxn],n,m,tp,mmax,jc[maxn];
  25. bool vis[maxn];
  26. std::map<ull,int> mp[maxn];
  27. int dfs(int now,int lat){
  28. if(now>n){
  29. return 1;
  30. }
  31. memset(b,0,sizeof(b));
  32. for(rg int i=1;i<=tp;i++){
  33. if(i!=lat) b[sta[i]]++;
  34. }
  35. ull nans=sta[0];
  36. for(rg int i=0;i<=mmax;i++){
  37. nans=nans*bas+b[i];
  38. }
  39. nans=nans*bas+sta[lat];
  40. if(mp[now].find(nans)!=mp[now].end()) return mp[now][nans];
  41. rg int mans=0;
  42. if(sta[0]>0){
  43. sta[0]--;
  44. mans=((long long)mans+(long long)dfs(now+1,0))%mod;
  45. sta[0]++;
  46. }
  47. for(rg int i=1;i<=tp;i++){
  48. if(i!=lat && sta[i]>0){
  49. sta[i]--;
  50. mans=((long long)mans+(long long)dfs(now+1,i))%mod;
  51. sta[i]++;
  52. }
  53. }
  54. mp[now][nans]=mans;
  55. return mans;
  56. }
  57. int main(){
  58. n=read();
  59. for(rg int i=1;i<=n;i++){
  60. a[i]=read();
  61. }
  62. m=read();
  63. for(rg int i=1;i<=n;i++){
  64. a[i]%=m;
  65. if(a[i]<0) a[i]+=m;
  66. }
  67. rg int ncnt=0;
  68. for(rg int i=1;i<=n;i++){
  69. if(vis[i]) continue;
  70. vis[i]=1;
  71. ncnt=0;
  72. for(rg int j=i;j<=n;j++){
  73. if(a[i]==a[j]){
  74. vis[j]=1;
  75. ncnt++;
  76. }
  77. }
  78. mmax=std::max(mmax,ncnt);
  79. if(ncnt==1) sta[0]++;
  80. else sta[++tp]=ncnt;
  81. }
  82. jc[0]=1;
  83. for(rg int i=1;i<=n;i++){
  84. jc[i]=1LL*jc[i-1]*i%mod;
  85. }
  86. rg int ans=1;
  87. for(rg int i=0;i<=tp;i++){
  88. ans=1LL*ans*jc[sta[i]]%mod;
  89. }
  90. ans=1LL*ans*dfs(1,0)%mod;
  91. printf("%d\n",ans);
  92. return 0;
  93. }

SSY的队列 hash+记忆化的更多相关文章

  1. [HNOI2013]比赛 (用Hash实现记忆化搜索)

    [HNOI2013]比赛 题目描述 沫沫非常喜欢看足球赛,但因为沉迷于射箭游戏,错过了最近的一次足球联赛.此次联 赛共N支球队参加,比赛规则如下: (1) 每两支球队之间踢一场比赛. (2) 若平局, ...

  2. TC-572-D1L2 (双向搜索+记忆化)

    solution: 这一题是比较难实现的双向搜索题:(字符串+双向搜索+hash记忆化) 我们可以先把K的前半部分枚举出来,并将得出的所有结果和题目给的n个数的每一个数的前半部分都比对一遍,得到它和每 ...

  3. LuoguP2254 [NOI2005]瑰丽华尔兹 (单调队列优化DP)(用记忆化过了。。。)

    记忆化 #include <cstdio> #include <iostream> #include <cstring> #include <algorith ...

  4. FZU 2092 bfs+记忆化搜索

    晚上团队训练赛的题 和普通bfs不同的是 这是同时操纵人与影子两个单位进行的bfs 由于可能发生人和影子同时接触水晶 所以不可以分开操作 当时使用node记录人和影子的位置 然后进行两重for循环来分 ...

  5. FZU 2092 收集水晶 bfs+记忆化搜索 or 暴力

    题目链接:收集水晶 一眼看过去,觉得是普通的bfs,初始位置有两个.仔细想了想...好像如果这样的话..........[不知道怎么说...T_T] dp[12][12][12][12][210] 中 ...

  6. (中等) POJ 1054 The Troublesome Frog,记忆化搜索。

    Description In Korea, the naughtiness of the cheonggaeguri, a small frog, is legendary. This is a we ...

  7. (区间dp + 记忆化搜索)Treats for the Cows (POJ 3186)

    http://poj.org/problem?id=3186   Description FJ has purchased N (1 <= N <= 2000) yummy treats ...

  8. hdu1428 记忆化搜索(BFS预处理最短路径和+DP+DFS)

    题意:有一块 n * n 大小的方形区域,要从左上角 (1,1)走到右下角(n,n),每个格子都有通过所需的时间,并且每次所走的下一格到终点的最短时间必须比当前格子走到重点的最短时间短,问一共有多少种 ...

  9. tyvj 1004 滑雪 记忆化搜索

    滑雪 Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://www.tyvj.cn/p/1004 Description     trs喜欢滑雪.他来 ...

随机推荐

  1. elasticsearch练习

    elasticsearch练习 最近在学习elasticsearch,做了一些练习,分享下练习成果,es基于6.7.2,用kibana处理DSL,有兴趣的伙伴可以自己试试 1.简单查询练习 sourc ...

  2. 可变数据类型不能作为python函数的参数

    可变数据类型:列表.字典 不可变数据类型:整型.浮点型.字符串.元组 为什么可变数据类型不能作为python函数的参数?请看以下例子: def foo(a=[]): a.append(1) retur ...

  3. lumen单元测试

    phpunit --filter testInfo  tests/UserTest.php UserTest.php <?php use Laravel\Lumen\Testing\Databa ...

  4. scrapy数据写入管道

    1 setting里面启动管道 ITEM_PIPELINES = { 'ganji.pipelines.GanjiPipeline': 300,}2 拿到的数据通过yield返回给管道 # -*- c ...

  5. Spring In Action 5th中的一些错误

    引言 最近开始学习Spring,了解到<Spring实战>已经出到第五版了,遂打算跟着<Spring实战(第五版)>来入门Spring,没想到这书一点也不严谨,才看到第三章就发 ...

  6. scrapy爬取豆瓣电影信息

    最近在学python,对python爬虫框架十分着迷,因此在网上看了许多大佬们的代码,经过反复测试修改,终于大功告成! 原文地址是:https://blog.csdn.net/ljm_9615/art ...

  7. codefroces中的病毒,这题有很深的trick,你能解开吗?

    大家好,欢迎阅读周末codeforces专题. 我们今天选择的问题是contest 1419的C题,目前有接近8000的人通过了本题.今天这题的难度不大,但是真的很考验思维,一不小心就会踩中陷阱,我个 ...

  8. 【新阁教育】S7.NET+Log4Net+SQLSugar+MySQL搭建Iot平台

    1.搭建西门子S7仿真环境 新阁教育提醒您基于PLCSIM-Advanced搭建西门子S7仿真环境注意事项: 1.通过dotNet工控上位机公众号后台发送PLCSIM-Advanced获取软件 2.安 ...

  9. Linux 系统编程 学习:008-基于socket的网络编程3:基于 TCP 的通信

    背景 上一讲我们介绍了 基于UDP 的通信 这一讲我们来看 TCP 通信. 知识 TCP(Transmission Control Protoco 传输控制协议). TCP是一种面向广域网的通信协议, ...

  10. [BZOJ 2287/POJ openjudge1009/Luogu P4141] 消失之物

    题面: 传送门:http://poj.openjudge.cn/practice/1009/ Solution DP+DP 首先,我们可以很轻松地求出所有物品都要的情况下的选择方案数,一个简单的满背包 ...