为什么网上没有篇详细的题解【雾

可能各位聚聚觉得这道题太简单了吧 /kk

题意

首先题目是求满足条件的序列个数,条件为:出现次数最多的数仅有一个

分析

感谢 刚睡醒的 JZ姐姐在咱写题解忽然陷入自闭的时候为咱知道迷津 QwQ

那么套路来说第一想到的其实就是容斥辣 然后懒得想去网上黈力【雾

在然后,发现网上要么没推导公式(虽说是直接列不用化简的)要么就是推导公式是错的...

于是坐下来冷静分析:首先,我们考虑最高的出现次数为 x 的情况下,有多少个序列是满足条件的

容斥一发发现式子长这个样子(用到了隔板法,然后容斥顺便也能把有数字出现次数高于 x 的情况给容掉)

\[ans(x)=m\sum_{j=0}^{m-1} (-1)^j \binom{n-x*(j+1) + m-2 }{m-2}
\]

大概是说,我们确定最高次数为 x ,那么我们先钦定一个数为恰好出现 x 次的数,然后剩下 m-1 个数插板容斥求方案 QwQ ,于是我们就可以递推求解辣:

\[ANS=\sum_{i=\lceil \frac{n}{m} \rceil }^n m\sum_{j=0}^{m-1} (-1)^j \binom{n-i*(j+1)+m-2} {m-2}
\]

然后我们发现复杂度爆炸了呢 Σ(⊙▽⊙"a 管他呐,交上去就好辣

然后咱发现后面那个式子如果 \(n-i*(j+1)+m-2\) 大于 \(m-2\) 的话贡献为 0 ,一顿计算发现 j 要小于 n/i 才有贡献,那么第二个枚举的上界的 m-1 改一改就好咯...

\[ANS=\sum_{i=\lceil \frac{n}{m} \rceil }^n m\sum_{j=0}^{min(m-1,n/i-1)} (-1)^j \binom{n-i*(j+1)+m-2} {m-2}
\]

然后调和级数分析一波,发现复杂度是 \(n·H(n)\) 的,能过...

顺便稍微讲讲带限制的板怎么插好了 QAQ

注意这里说的限制是对于任意两个隔板之间的元素数量而言,如果隔板间元素数量的限制是不同,可能需要什么黑科技(反正咱只会指数级别容斥【逃)

那么假设现在有 n 个元素,要分成 m 堆元素,也就是有 m-1 个插板

0.不带限制的插板

显然是 \(\binom{n+m-1}{m-1}\)

意思就是我们把 n 个元素和 m-1 个插板排成一列,计算方案数

那么我们只要计算 m-1 个插板有多少种摆法就好了,隔板确定完了,元素的放法自然就确定了

说白了就是求了个 m-1 个插板在所有 n+m-1 个物品中的位置方案数

1.带下界的插板

假设下界为 x ,即隔出来的每堆元素数量不小于 x

答案是 \(\binom{n+m-m·x-1}{m-1}\)

我们发现这玩意儿比较简单,只要把原本要拿来插板的元素先减去 \(m*x\) (也就是预先给每堆元素分掉这个下界 ) 然后再去插板就好辣

2.(JZ 姐姐教的QwQ)带上界的插板

假设上界为 x ,即隔出来的每堆元素数量不大于 x

答案是 \(\sum_{i=0}^{m} (-1)^i \binom{m}{j} \binom{n+m-i*(x+1)-1}{m-1}\)

有容斥呢 QwQ 解释一下,就是说我们枚举超出上限的元素堆个数,然后强制他们选了 (x+1) 个,这样不管它们接下来怎么选都已经超限了,然后我们加个 \((-1)\) 的幂次容斥一下就好辣

如果康不懂的话请重修容斥 QvQ

这样咱发现上面的那个式子一下子就很明了了呢 QvQ

Code

注意阶乘及逆元的 1e5 数组是假的,要两倍的!花了咱 5 点头盾 get 到的细节 【枯

  1. //by Judge
  2. #define HGS_AK_IOI true
  3. #include<bits/stdc++.h>
  4. #define mod 1000000007
  5. #define Rg register
  6. #define fp(i,a,b) for(Rg int i=(a),I=(b)+1;i<I;++i)
  7. #define fd(i,a,b) for(Rg int i=(a),I=(b)-1;i>I;--i)
  8. #define go(u) for(Rg int i=head[u],v=e[i].to;i;v=e[i=e[i].nxt].to)
  9. #define open(S) freopen(S".in","r",stdin),freopen(S".out","w",stdout)
  10. #define ll long long
  11. using namespace std;
  12. const int M=2e5+3;
  13. typedef int arr[M];
  14. #ifndef Judge
  15. #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
  16. #endif
  17. char buf[1<<21],*p1=buf,*p2=buf;
  18. template<class T>inline T Min(T x,T y){return x<y?x:y;}
  19. template<class T>inline T Max(T x,T y){return x>y?x:y;}
  20. template<class T>inline bool cmax(T& a,T b){return a<b?a=b,1:0;}
  21. template<class T>inline bool cmin(T& a,T b){return a>b?a=b,1:0;}
  22. inline int read(){ int x=0,f=1; char c=getchar();
  23. for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
  24. for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;
  25. } int n,m,ans; arr fac,inv;
  26. inline int mul(int x,int y){return 1ll*x*y%mod;}
  27. inline void Pls(int& x,int y){if((x+=y)>=mod)x-=mod;}
  28. inline int qpow(int x,int p=mod-2){ Rg int s=1;
  29. for(;p;p>>=1,x=mul(x,x)) if(p&1) s=mul(s,x); return s;
  30. }
  31. inline void prep(int n=2e5){
  32. fac[0]=1; fp(i,1,n) fac[i]=mul(fac[i-1],i);
  33. inv[n]=qpow(fac[n]); fd(i,n,1) inv[i-1]=mul(inv[i],i);
  34. }
  35. inline int Ceil(int x,int y){ return x%y>0?x/y+1:x/y; }
  36. inline int C(int n,int m){ if(n<m) return 0;
  37. return mul(fac[n],mul(inv[m],inv[n-m]));
  38. }
  39. inline void Solv(){ n=read(),m=read(),ans=0;
  40. if(m==1) return printf("1\n"),void();
  41. if(n==1) return printf("%d\n",m),void();
  42. fp(i,Ceil(n,m),n) fp(j,0,Min(n/i-1,m-1))
  43. Pls(ans,mul(j&1?(mod-1):1, mul(C(m-1,j),C(n+m-i*(j+1)-2,m-2)) ));
  44. printf("%d\n",mul(ans,m));
  45. }
  46. int main(){
  47. #ifdef Judge
  48. freopen("1.in","r",stdin);
  49. #endif
  50. int T=read(); prep();
  51. while(T--) Solv(); return 0;
  52. }

【51nod 1251】 Fox序列的数量(以及带限制插板法讲解)的更多相关文章

  1. 51nod 1251 Fox序列的数量 (容斥)

    枚举最多数字的出现次数$k$, 考虑其他数字的分配情况. 对至少$x$种数出现$\ge k$次的方案容斥, 有 $\sum (-1)^x\binom{m-1}{x}\binom{n-(x+1)k+m- ...

  2. 【51nod】1251 Fox序列的数量

    题解 容斥题 我们枚举出现次数最多的数出现了K次 然后我们需要计算的序列是所有数字出现个数都不超过K - 1次 我们枚举不合法的数字的数目j,说明这个排列里除了我们固定出现K次的数至少有j个数是不合法 ...

  3. (转)AS3正则:元子符,元序列,标志,数量表达符

    (转)AS3正则:元子符,元序列,标志,数量表达符: AS3正则:元子符,元序列,标志,数量表达符 七月 4th, 2010 归类于 AS3前端技术 作者Linkjun 进行评论 as3正则:元子符, ...

  4. Java实现蓝桥杯模拟正整数序列的数量

    问题描述 小明想知道,满足以下条件的正整数序列的数量: 1. 第一项为 n: 2. 第二项不超过 n: 3. 从第三项开始,每一项小于前两项的差的绝对值. 请计算,对于给定的 n,有多少种满足条件的序 ...

  5. Comparing Your Heros拓扑序列的数量

    给出N行英雄的比较,每一行包含两个英雄的名字,代表第一个英雄比第二个英雄更受欢迎. 英雄的数目不超过16个.问有多少种可能的受欢迎程度的序列满足N行英雄的比较. 由于只有英雄数目不超过16个,可以用二 ...

  6. 51nod 1042数字0-9的数量

    1042 数字0-9的数量  基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题  收藏  关注 给出一段区间a-b,统计这个区间内0-9出现的次数. 比如 10-19 ...

  7. 51nod 1042 数字0-9的数量 数位dp

    1042 数字0-9的数量 基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题  收藏  关注 给出一段区间a-b,统计这个区间内0-9出现的次数.   比如 10-1 ...

  8. 【BZOJ】【1251】序列终结者

    Splay 还是splay序列维护,这题我WA了的原因是:在Push_up的时候,当前子树的max我是直接取的L.R和v[x]的最大值,但是如果没有左/右儿子,默认是会访问0号结点的mx值,而这个值没 ...

  9. 51nod 1522 上下序列

    题目描述 现在有1到n的整数,每一种有两个.要求把他们排在一排,排成一个2*n长度的序列,排列的要求是从左到右看,先是不降,然后是不升. 特别的,也可以只由不降序列,或者不升序列构成. 例如,下面这些 ...

随机推荐

  1. Linux简单检查服务运行脚本

    脚本内容如下: 此脚本含义:检查服务是否运行,在运行则记录日志,不在运行则记录日志并将服务启动 #!/bin/bash svrnm="tomcat" //设置服务名称time=`d ...

  2. JVM Java字节码的角度分析switch的实现

    目录 Java字节码的角度分析switch的实现 引子 前置知识 一个妥协而又枯燥的方案 switch的实现 回顾历史 字节码分析 其他实现方式? Java字节码的角度分析switch的实现 作者 k ...

  3. Spring Cloud 入门系列(一)

    前言 Spring Could作为目前最流行基于Java开发的构建微服务的完整框架.发现目前相关系列教程太少,本文是基于官网教程做的一套翻译. 何为Spring Cloud? Spring Cloud ...

  4. 并发新构件之CountDownLatch

    CountDownLatch译为倒计时锁存器:JDK描述     :允许一个或多个线程等待直到在其他线程中执行的一组操作完成的同步辅助. A CountDownLatch用给定的计数初始化. awai ...

  5. 1046 Shortest Distance (20 分)

    1046 Shortest Distance (20 分) The task is really simple: given N exits on a highway which forms a si ...

  6. JDK8 Optional操作学习

    介绍 Optional是JDK8中提供用于包含未知对象的工具类,即可以利用Optional包装对象来避免繁琐的空指针检查,以及NullPointException的处理,在Optional中,用val ...

  7. django中CBV

    08.13自我总结 django中CBV 一.django处理业务逻辑的两种方式 FBV (function based views):使用函数来处理业务逻辑 CBV (class based vie ...

  8. 实验吧之【因缺思汀的绕过】(group by with rollup的注入利用)

    打开页面,查看源代码,发现存在source.txt(http://ctf5.shiyanbar.com/web/pcat/source.txt),如下: <?php error_reportin ...

  9. Python开发【第十一篇】函数

    函数 什么是函数? 函数是可以重复执行的语句块,可以重复调用并执行函数的面向过程编程的最小单位. 函数的作用: 函数用于封装语句块,提高代码的重用性,定义用户级别的函数.提高代码的可读性和易维护性. ...

  10. JS实现生成一个周对应日期数组

    /* 获取日期和周 */ getDateWeek() {/* 得到当前日期的时间戳 */ const timestamp = Date.now() // const timestamp = new D ...