[bzoj3142] [HNOI2013]数列

Description

小T最近在学着买股票,他得到内部消息:F公司的股票将会疯涨。股票每天的价格已知是正整数,并且由于客观上的原因,最多只能为N。在疯涨的K天中小T观察到:除第一天外每天的股价都比前一天高,且高出的价格(即当天的股价与前一天的股价之差)不会超过M,M为正整数。并且这些参数满足M(K-1)<N。
小T忘记了这K天每天的具体股价了,他现在想知道这K天的股价有多少种可能

Input

只有一行用空格隔开的四个数:N、K、M、P。对P的说明参见后面“输出格式”中对P的解释。
输入保证20%的数据M,N,K,P≤20000,保证100%的数据M,K,P≤109,N≤1018 。

Output

仅包含一个数,表示这K天的股价的可能种数对于P的模值。【输入输出样例】

Sample Input

7 3 2 997             

Sample Output

16

Solution

设每天的股价为\(a[1]...a[k]\),考虑它的差分序列\(s[1]...s[k-1]\)

由于最多不能超过\(n\),所以\(a[1]\)的取值就有\(n-\sum_{i=1}^{k-1}s[i]\)种情况。

考虑差分序列每一位最多是\(m\),所以差分序列一共有\(m^{k-1}\)种,设第\(d\)种第\(i\)位为\(s[d][i]\)

所以答案就是:

\[\begin{align} &\sum_{d=1}^{m^{k-1}}(n-\sum_{i=1}^{k-1}s[d][i])\\ =&n\cdot m^{k-1}-\sum_{d=1}^{m^{k-1}}\sum_{i=1}^{k-1}s[d][i] \end{align} \]

考虑到后面一项共有\(m^{k-1}\cdot (k-1)\),而\(s[d][i]\)又在\([1,m]\)上均匀分布,所以最后一项就等于:

\[m^{k-2}\cdot (k-1)\cdot \frac{m(m+1)}{2} \]

然后带上去快速幂一下就行了。

#include<bits/stdc++.h>
using namespace std;

#define int long long 

#define ONLINE_JUDGE

#ifdef ONLINE_JUDGE
#define getchar() ((p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin)),p1==p2)?EOF:*p1++)
#endif

namespace fast_IO {
	
	char buf2[1<<21],a[80];int p,p3=-1;
	char buf[1<<21],*p1=buf,*p2=buf;
	
	template <typename T> inline void read(T &x) {
		x=0;T f=1;char ch=getchar();
		for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
		for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
	}
	template <typename T,typename... Args> inline void read(T& x,Args& ...args) {
		read(x),read(args...);
	}

	inline void flush() {fwrite(buf2,1,p3+1,stdout),p3=-1;}
	template <typename T> inline void write(T x) {
		if(p3>(1<<20)) flush();
		if(x<0) buf2[++p3]='-',x=-x;
		do {a[++p]=x%10+48;} while(x/=10);
		do {buf2[++p3]=a[p];} while(--p);
		buf2[++p3]='\n';
	}
	template <typename T,typename... Args> inline void write(T x,Args ...args) {
		write(x),write(args...);
	}
}

using fast_IO :: read;
using fast_IO :: write;
using fast_IO :: flush;

int n,k,m,p;

int qpow(int a,int x) {
	int res=1;
	for(;x;x>>=1,a=a*a%p) if(x&1) res=res*a%p;
	return res;
}

signed main() {
	read(n,k,m,p);n%=p;
	write(((qpow(m,k-1)*n%p-m*(m+1)/2%p*qpow(m,k-2)%p*(k-1)%p)%p+p)%p);
	flush();
	return 0;
}
posted @ 2018-12-28 17:02  Hyscere  阅读(137)  评论(0编辑  收藏  举报