BZOJ-3142 [Hnoi2013]數列(差分+計數)
阿新 • • 發佈:2020-12-08
題目描述
有一個長為 \(k\) 的嚴格單調遞增序列,最大值為 \(n\),相鄰兩數之差不超過 \(m\)(即 \(a_i-a_{i-1}\leq m\)),求滿足條件的方案數,答案對 \(p\) 取模。
資料範圍:\(n\leq 10^{18},m,k,p\leq 10^9\)。
分析
序列第一個數 \(a_1\) 的取值難以確定,考慮把序列差分一下(\(c_i=a_i-a_{i-1}(2\leq i\leq n)\)),得到差分序列:\(c_1,c_2,\cdots,c_{k-1}\),合法序列條件為 \(\forall i\in[1,k-1],1\leq c_i\leq m\)。
設 \(f(c)\) 為差分序列 \(c\) 對答案的貢獻,對於同一個差分序列 \(c\),它對答案的貢獻為 \(n-\displaystyle\sum_{i=1}^{k-1}c_i\),即:
\[f(c)=n-\displaystyle\sum_{i=1}^{k-1}c_i \]由於合法序列條件為 \(\forall i\in[1,k-1],1\leq c_i\leq m\),所以一共有 \(m^{k-1}\) 種差分序列。則答案為:
\[\sum_{i=1}^{m^{k-1}}f(c)=\sum_{i=1}^{m^{k-1}}(n-\sum_{j=1}^{k-1}c_j)=n\times m^{k-1}-\sum_{i=1}^{m^{k-1}}\sum_{j=1}^{k-1}c_j \]後面的式子代表序列 \(c=[c_1,c_2,\cdots,c_{k-1}](1\leq c_i\leq m)\) 的所有排列之和,一共有 \(m^{k-1}·(k-1)\) 個數字。\(1\) ~ \(m\) 中的每個數都在所有排列中出現了恰好 \(\frac{m^{k-1}·(k-1)}{m}=m^{k-2}·(k-1)\) 次,總和即為 \(m^{k-2}·(k-1)·\frac{m(m+1)}{2}\)。
因此答案為:
\[n\times m^{k-1}-m^{k-2}·(k-1)·\frac{m(m+1)}{2} \]程式碼
#include<bits/stdc++.h> using namespace std; long long n,m,k,p; long long quick_pow(long long a,long long b,long long p) { long long ans=1; while(b) { if(b&1) ans=ans*a%p; a=a*a%p; b>>=1; } return ans%p; } int main() { cin>>n>>k>>m>>p; n=n%p;m=m%p; long long ans1=quick_pow(m,k-1,p); ans1=ans1*n%p; long long ans2=m*(m+1)/2%p*quick_pow(m,k-2,p)%p*(k-1)%p; cout<<((ans1-ans2)%p+p)%p<<endl; return 0; }