题目
小T最近在学着买股票,他得到内部消息:F公司的股票将会疯涨。
股票每天的价格已知是正整数,并且由于客观上的原因,最多只能为N。在疯涨的K天中小T观察到:除第一天外每天的股价都比前一天高,且高出的价格(即当天的股价与前一天的股价之差)不会超过M,M为正整数。并且这些参数满足M(K-1)
分析
我们发现若是从他们的各自股价开始入手,问题会变得很困难,
为什么呢?因为股价本身就是一个递增的值,不方便我们讨论方案数
于是我们可以从有限定的m入手,即每两天之间股价的差:
a[1],a[2],a[3],a[4]..a[k-1]
那么这样就不用去管每个a[i]的值之间的关系了。
若是确定了这k-1个数,那么很明显会有
n−∑a[i]
的方案(即第一天的股价的值)
那么总的方案就是
∑n−∑a[i]
然而这样想上面的数列一共有
mk−1
,我们先提取n出来,就是
n∗mk−1
而a[i]我们可以这样处理,因为一共有
mk−1
个数列,也就是有
mk−1∗(k−1)
个数
而且每一个数的范围都是1..m,出现的次数都是一样的也就是
mk−1∗(k−1)/m=mk−2∗(k−1)
这样的话,用等差数列求和,每m个数配一组总的就是
mk−2∗(k−1)∗(m+1)∗m/2
所以答案就是
n∗mk−1−mk−2∗(k−1)∗(m+1)∗m/2
到此便很好的解决问题了。这题关键是转换成差来思考。
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<cstdio>
using namespace std;
long long ans,n,m,k,p;
long long power(long long x,long long y,long long z){
if (y==1) return x;
else {
long long e=power(x,y>>1,z);
e=(e*e)%p;
if (y%2==1) e=(e*x)%p;
return e;
}
}
int main(){
scanf("%lld%d%d%d",&n,&k,&m,&p);
n=n%p;
ans=(power(m % p,k-1,p)*(n%p))%p;
ans-=((power(m % p,k-2,p)*(k-1)% p)*(((m+1)*m/2)% p))%p;
ans=(ans+p)%p;
printf("%d",ans);
}