DestinHistoire

 

BZOJ-3142 [Hnoi2013]数列(差分+计数)

题目描述

  有一个长为 \(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;
}

posted on 2020-12-08 18:30  DestinHistoire  阅读(49)  评论(0编辑  收藏  举报

导航