题目描述 Description
小T最近在学着买股票,他得到内部消息:F公司的股票将会疯涨。
股票每天的价格已知是正整数,并且由于客观上的原因,最多只能为
N
N
。在疯涨的天中小T观察到:除第一天外每天的股价都比前一天高,且高出的价格(即当天的股价与前一天的股价之差)不会超过
M
M
,为正整数。并且这些参数满足
M∗(K−1)<N
M
∗
(
K
−
1
)
<
N
。
小T忘记了这
K
K
天每天的具体股价了,他现在想知道这天的股价有多少种可能。
输入描述 Input Description
输入文件只有一行用空格隔开的四个数:
N,K,M,P
N
,
K
,
M
,
P
输出描述 Output Description
仅包含一个数,表示这
K
K
天的股价的可能种数对于P的模值
样例输入 Sample Input
7 3 2 997
样例输出 Sample Output
16
样例解释
输出样例的16表示输入样例的股价有16种可能:
{1,2,3},{1,2,4},{1,3,4},{1,3,5},
{2,3,4},{2,3,5},{2,4,5},{2,4,6},
{3,4,5},{3,4,6},{3,5,6},{3,5,7},
{4,5,6},{4,5,7},{4,6,7},{5,6,7}
数据范围及提示 Data Size & Hint
20%的数据
100%的数据
K,M,P≤109,N≤1018
K
,
M
,
P
≤
10
9
,
N
≤
10
18
Solution
将某一个确定的上涨序列
a[1],a[2],a[3],...,a[k]
a
[
1
]
,
a
[
2
]
,
a
[
3
]
,
.
.
.
,
a
[
k
]
写出来
这个序列对于总数的贡献为1,当然,是当
a[k]≤n
a
[
k
]
≤
n
的时候
显然的,维持每天上涨的价格不变,由于
a[1]
a
[
1
]
能够有多种取值,那么它就会有很多贡献,当然,变化后的
a[1]
a
[
1
]
仍然要保证
a[k]≤n
a
[
k
]
≤
n
那么能不能考虑维护一个股票价格的差分数列?就不用考虑
a[1]
a
[
1
]
的取值
并且,这个差分数列
s[1],s[2],s[3],...,s[k−1]
s
[
1
]
,
s
[
2
]
,
s
[
3
]
,
.
.
.
,
s
[
k
−
1
]
所做出的贡献就为
n−∑k−1i=1s[i]
n
−
∑
i
=
1
k
−
1
s
[
i
]
一共有
mk−1
m
k
−
1
个不同的差分数列,每个数列做出的贡献值为
n−∑k−1i=1s[i]
n
−
∑
i
=
1
k
−
1
s
[
i
]
那么总贡献就为
∑mk−1d=1(n−∑k−1i=1s[d][i])
∑
d
=
1
m
k
−
1
(
n
−
∑
i
=
1
k
−
1
s
[
d
]
[
i
]
)
将
n
n
提出可得
现在要做的就是处理后面那一堆东西
注意,
s
s
显然是将所有可能的排列情况都算了进去,并且
那么后面一共就会有
mk−1∗(k−1)
m
k
−
1
∗
(
k
−
1
)
个数,并且在
[1,m]
[
1
,
m
]
中完全平均分布
所以
[1,m]
[
1
,
m
]
中的每个数都会出现
mk−1∗(k−1)m=mk−2∗(k−1)
m
k
−
1
∗
(
k
−
1
)
m
=
m
k
−
2
∗
(
k
−
1
)
次
运用小学数学知识,将其总和化为
mk−2∗(k−1)∗(m+1)∗m2
m
k
−
2
∗
(
k
−
1
)
∗
(
m
+
1
)
∗
m
2
这样就很好求解了
最终答案为
n∗mk−1−mk−2∗(k−1)∗(m+1)∗m2
n
∗
m
k
−
1
−
m
k
−
2
∗
(
k
−
1
)
∗
(
m
+
1
)
∗
m
2
快速幂就好啦╮(╯_╰)╭
努力追赶dalao中
给予我力量吧(丢脸ing
代码如下
#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll n,k,m,p,ans;
ll read() {
ll ans=0,flag=1;
char ch=getchar();
while((ch>'9' || ch<'0') && ch!='-') ch=getchar();
if(ch=='-') flag=-1,ch=getchar();
while(ch>='0' && ch<='9') ans=ans*10+ch-'0',ch=getchar();
return ans*flag;
}
ll qpow(ll a,ll b,ll mod) {
ll ans=1;
while(b>0) {
if(b&1) {ans*=a;ans%=mod;}
b>>=1;a*=a;a%=mod;
}
return ans;
}
ll exgcd(ll a,ll b,ll &x,ll &y) {
if(b==0) {x=1;y=0;return a;}
ll gcd=exgcd(b,a%b,x,y);
ll t=x;
x=y; y=t-(a/b)*y;
}
int main() {
n=read(),k=read(),m=read(),p=read();
ll x,y,gcd;
gcd=exgcd(2,p,x,y);
x=(x%p+p)%p;
ans+=(qpow(m,k-1,p)*(n%p))%p;
ans-=((((qpow(m,k-1,p)*(k-1))%p*(m+1))%p)%p*x%p);
ans=(ans%p+p)%p;
printf("%lld\n",ans);
return 0;
}