BZOJ3142: [Hnoi2013]数列
3142: [Hnoi2013]数列
Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 657 Solved: 338
[Submit][Status]
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
【样例解释】
输出样例的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}
【样例解释】
输出样例的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}
HINT
Source
题解:
兰多夫:
我们可以枚举每两天的差值,对于每一个差值序列a[1],a[2],...,a[k-1]
有N-a[1]-a[2]-...-a[k-1]种方法,然后求和
因为N>M(K-1),所以一共有M^(K-1)个不同的序列
ans加上一个N*M^(K-1),再考虑减法的部分
M^(K-1)个数列一共有M^(K-1)*(K-1)个数字,1到M出现次数是一样的,为M^(K-2)*(K-1)
所以ans减去M^(K-1)*(K-1)*(M+1)/2
ans=N*M^(K-1)-M^(K-1)*(K-1)*(M+1)/2
最后一步建议不要把k搞上去,否则后出现模除法,而模数没有保证是质数,比较麻烦。
所以ans=n*k^(m-1)-k^(m-2) *(m-1)*(k)*(k+1)/2
提公因式之后是 k^(m-2) *(nk-(m-1)*k*(k+1)/2)
真是道巧妙的好题!
代码:
View Code
最后一步建议不要把k搞上去,否则后出现模除法,而模数没有保证是质数,比较麻烦。
所以ans=n*k^(m-1)-k^(m-2) *(m-1)*(k)*(k+1)/2
提公因式之后是 k^(m-2) *(nk-(m-1)*k*(k+1)/2)
真是道巧妙的好题!
代码:
1 #include<cstdio> 2 3 #include<cstdlib> 4 5 #include<cmath> 6 7 #include<cstring> 8 9 #include<algorithm> 10 11 #include<iostream> 12 13 #include<vector> 14 15 #include<map> 16 17 #include<set> 18 19 #include<queue> 20 21 #include<string> 22 23 #define inf 1000000000 24 25 #define maxn 500+100 26 27 #define maxm 500+100 28 29 #define eps 1e-10 30 31 #define ll long long 32 33 #define pa pair<int,int> 34 35 #define for0(i,n) for(int i=0;i<=(n);i++) 36 37 #define for1(i,n) for(int i=1;i<=(n);i++) 38 39 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 40 41 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 42 43 #define mod 1000000007 44 45 using namespace std; 46 47 inline ll read() 48 49 { 50 51 ll x=0,f=1;char ch=getchar(); 52 53 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 54 55 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 56 57 return x*f; 58 59 } 60 ll n,m,k,p; 61 inline ll power(ll x,ll y) 62 { 63 ll t=1; 64 for(;y;y>>=1,x=(x*x)%p) 65 if(y&1)t=(t*x)%p; 66 return t; 67 } 68 69 int main() 70 71 { 72 73 freopen("input.txt","r",stdin); 74 75 freopen("output.txt","w",stdout); 76 77 n=read();m=read();k=read();p=read(); 78 printf("%lld\n",(power(k,m-2)*(((n%p)*(k%p)-((m-1)%p)*((k*(k+1)/2)%p))%p+p)%p)%p); 79 80 return 0; 81 82 }