您的位置:首页 > 其它

[题解] BZOJ 3142 [HNOI2013]数列

2018-03-16 20:53 218 查看
题目描述 Description

小T最近在学着买股票,他得到内部消息:F公司的股票将会疯涨。

股票每天的价格已知是正整数,并且由于客观上的原因,最多只能为NN。在疯涨的KK天中小T观察到:除第一天外每天的股价都比前一天高,且高出的价格(即当天的股价与前一天的股价之差)不会超过MM,MM为正整数。并且这些参数满足M∗(K−1)<NM∗(K−1)<N。

小T忘记了这KK天每天的具体股价了,他现在想知道这KK天的股价有多少种可能。

输入描述 Input Description

输入文件只有一行用空格隔开的四个数:N,K,M,PN,K,M,P

输出描述 Output Description

仅包含一个数,表示这KK天的股价的可能种数对于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%的数据M,N,K,P≤20000M,N,K,P≤20000

100%的数据K,M,P≤109,N≤1018K,M,P≤109,N≤1018

Solution

将某一个确定的上涨序列a[1],a[2],a[3],...,a[k]a[1],a[2],a[3],...,a[k]写出来

这个序列对于总数的贡献为1,当然,是当a[k]≤na[k]≤n的时候

显然的,维持每天上涨的价格不变,由于a[1]a[1]能够有多种取值,那么它就会有很多贡献,当然,变化后的a[1]a[1]仍然要保证a[k]≤na[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=1k−1s[i]

一共有mk−1mk−1个不同的差分数列,每个数列做出的贡献值为n−∑k−1i=1s[i]n−∑i=1k−1s[i]

那么总贡献就为

∑mk−1d=1(n−∑k−1i=1s[d][i])∑d=1mk−1(n−∑i=1k−1s[d][i])

将nn提出可得

n∗mk−1−∑mk−1d=1∑k−1i=1s[d][i]n∗mk−1−∑d=1mk−1∑i=1k−1s[d][i]

现在要做的就是处理后面那一堆东西

注意,ss显然是将所有可能的排列情况都算了进去,并且s[d][i]∈[1,m]s[d][i]∈[1,m]

那么后面一共就会有mk−1∗(k−1)mk−1∗(k−1)个数,并且在[1,m][1,m]中完全平均分布

所以[1,m][1,m]中的每个数都会出现mk−1∗(k−1)m=mk−2∗(k−1)mk−1∗(k−1)m=mk−2∗(k−1)次

运用小学数学知识,将其总和化为mk−2∗(k−1)∗(m+1)∗m2mk−2∗(k−1)∗(m+1)∗m2

这样就很好求解了

最终答案为n∗mk−1−mk−2∗(k−1)∗(m+1)∗m2n∗mk−1−mk−2∗(k−1)∗(m+1)∗m2

快速幂就好啦╮(╯_╰)╭

努力追赶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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: