【51nod 1251】 Fox序列的數量(以及帶限制插板法講解)

爲何網上沒有篇詳細的題解【霧
可能各位聚聚以爲這道題太簡單了吧 /kkc++

題意

首先題目是求知足條件的序列個數,條件爲:出現次數最多的數僅有一個git

分析

感謝 剛睡醒的 JZ姐姐在咱寫題解突然陷入自閉的時候爲咱知道迷津 QwQ數組

那麼套路來講第一想到的其實就是容斥辣 而後懶得想去網上黈力【霧
在而後,發現網上要麼沒推導公式(雖然說是直接列不用化簡的)要麼就是推導公式是錯的...spa

因而坐下來冷靜分析:首先,咱們考慮最高的出現次數爲 x 的狀況下,有多少個序列是知足條件的
容斥一發發現式子長這個樣子(用到了隔板法,而後容斥順便也能把有數字出現次數高於 x 的狀況給容掉)code

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

大概是說,咱們肯定最高次數爲 x ,那麼咱們先欽定一個數爲剛好出現 x 次的數,而後剩下 m-1 個數插板容斥求方案 QwQ ,因而咱們就能夠遞推求解辣:it

\[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} \]class

而後咱們發現複雜度爆炸了呢 Σ(⊙▽⊙"a 管他吶,交上去就好辣di

而後咱發現後面那個式子若是 \(n-i*(j+1)+m-2\) 大於 \(m-2\) 的話貢獻爲 0 ,一頓計算髮現 j 要小於 n/i 纔有貢獻,那麼第二個枚舉的上界的 m-1 改一改就好咯...while

\[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 到的細節 【枯

//by Judge
#define HGS_AK_IOI true
#include<bits/stdc++.h>
#define mod 1000000007
#define Rg register
#define fp(i,a,b) for(Rg int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(Rg int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(Rg int i=head[u],v=e[i].to;i;v=e[i=e[i].nxt].to)
#define open(S) freopen(S".in","r",stdin),freopen(S".out","w",stdout)
#define ll long long
using namespace std;
const int M=2e5+3;
typedef int arr[M];
#ifndef Judge
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#endif
char buf[1<<21],*p1=buf,*p2=buf;
template<class T>inline T Min(T x,T y){return x<y?x:y;}
template<class T>inline T Max(T x,T y){return x>y?x:y;}
template<class T>inline bool cmax(T& a,T b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T& a,T b){return a>b?a=b,1:0;}
inline int read(){ int x=0,f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;
} int n,m,ans; arr fac,inv;
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline void Pls(int& x,int y){if((x+=y)>=mod)x-=mod;}
inline int qpow(int x,int p=mod-2){ Rg int s=1;
    for(;p;p>>=1,x=mul(x,x)) if(p&1) s=mul(s,x); return s;
}
inline void prep(int n=2e5){
    fac[0]=1; fp(i,1,n) fac[i]=mul(fac[i-1],i);
    inv[n]=qpow(fac[n]); fd(i,n,1) inv[i-1]=mul(inv[i],i);
}
inline int Ceil(int x,int y){ return x%y>0?x/y+1:x/y; }
inline int C(int n,int m){ if(n<m) return 0;
    return mul(fac[n],mul(inv[m],inv[n-m]));
}
inline void Solv(){ n=read(),m=read(),ans=0;
    if(m==1) return printf("1\n"),void();
    if(n==1) return printf("%d\n",m),void();
    fp(i,Ceil(n,m),n) fp(j,0,Min(n/i-1,m-1))
        Pls(ans,mul(j&1?(mod-1):1, mul(C(m-1,j),C(n+m-i*(j+1)-2,m-2)) ));
    printf("%d\n",mul(ans,m));
}
int main(){
#ifdef Judge
freopen("1.in","r",stdin);
#endif
    int T=read(); prep();
    while(T--) Solv(); return 0;
}
相關文章
相關標籤/搜索