3142: [Hnoi2013]数列
Time Limit: 3 Sec Memory Limit: 128 MB
Submit: 1744 Solved: 866
[Submit][Status][Discuss]
Description
小T最近在学着买股票,他得到内部消息:F公司的股票将会疯涨。股票每天的价格已知是正整数,并且由于客观上的原因,最多只能为N。在疯涨的K天中小T观察到:除第一天外每天的股价都比前一天高,且高出的价格(即当天的股价与前一天的股价之差)不会超过M,M为正整数。并且这些参数满足M(K-1)
sol:
很有趣的一道题。
看着20%的数据以为是100%的数据,因为我一开始只会n^2的做法。
我们考虑把这个序列拿去差分,那么一个差分序列提供的贡献是
n−∑ia[i]n−∑ia[i]
那很多个差分序列的话就是
∑j(n−∑ia[i])∑j(n−∑ia[i]) 枚举个j表示我们把a[i]数组给动了动,注意因为题目保证了m(k-1) < n所以这个式子完全成立的
提一提
n∗Mk−1−∑j∑ia[i]n∗Mk−1−∑j∑ia[i]
容易发现固定了某个位置上的某个数,单独算这个数的贡献的话,他会提供
Mk−2Mk−2次的贡献。能换位置的话就*(k-1).
既然每个数都这样,那就对数求个和,然后*后面的系数即可。
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
using namespace std;
typedef long long ll;
typedef double db;
ll n,m,k;
ll pyz;
inline ll ksm(ll s,ll t)
{
s%=pyz;
int res=1;
while(t)
{
if(t&1) res=(ll)res*s%pyz;
s=(ll)s*s%pyz;
t>>=1;
}
return res;
}
int main()
{
// freopen("3142.in","r",stdin);
// freopen(".out","w",stdout);
cin>>n>>k>>m>>pyz;
printf("%lld\n",(n%pyz*ksm(m,k-1)%pyz-m*(1+m)/2%pyz*ksm(m,k-2)%pyz*(k-1)%pyz+pyz)%pyz);
}