1. 程式人生 > 其它 >【洛谷P3228】數列

【洛谷P3228】數列

題目

題目連結:https://www.luogu.com.cn/problem/P3228
小 T 最近在學著買股票,他得到內部訊息:F 公司的股票將會瘋漲。股票每天的價格已知是正整數,並且由於客觀上的原因,最多隻能為 \(n\)。在瘋漲的 \(k\) 天中小 T 觀察到:除第一天外每天的股價都比前一天高,且高出的價格(即當天的股價與前一天的股價之差)不會超過 \(m\)\(m\) 為正整數。並且這些引數滿足 \(m(k-1)<n\)。小 T 忘記了這 \(k\) 天每天的具體股價了,他現在想知道這 \(k\) 天的股價有多少種可能。
\(m,k,p\leq 10^9;n\leq 10^{18}\)

思路

不難想到把每天的股價差分一下。那麼現在問題轉化為對於一個長度為 \(k-1\) 的序列 \(a\),且 \(a\) 的每一個元素都不超過 \(m\),它的貢獻是 \((n-\sum^{i=1}_{k-1}a_i)\)。求所有滿足要求的序列的貢獻之和。
顯然差分序列一共有 \(m^{k-1}\) 種。記 \(a_{i,j}\) 為第 \(i\) 種差分序列的第 \(j\) 個元素。那麼答案即為

\[\sum^{m^{k-1}}_{i=1}\left ( n-\sum_{j=1}^{k-1}a_{i,j}\right ) \]\[=n\times m^{k-1}-\sum^{m^{k-1}}_{i=1}\sum_{j=1}^{k-1}a_{i,j} \]

考慮減號後面一部分。也就是所有差分序列的所有元素和。
可以發現每一個 \([1,m]\)

間的數字的出現次數都是一樣的。因為對於兩個數字 \(x,y\),我們把所有差分序列中 \(x\)\(y\) 的位置交換,那麼這 \(m^{k-1}\) 個差分序列必然和沒有交換前的一致。
由於所有數字出現次數之和為 \(m^{k-1}\times (k-1)\),所以每一個數字的出現次數就為 \(m^{k-2}\times (k-1)\)。所以答案就是

\[n\times m^{k-1}-\frac{m(1+m)}{2}\times m^{k-2}\times (k-1) \]

程式碼

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

ll n,m,k,p;

ll fpow(ll x,ll k)
{
	ll ans=1;
	for (;k;k>>=1,x=x*x%p)
		if (k&1) ans=ans*x%p;
	return ans;
}

int main()
{
	scanf("%lld%lld%lld%lld",&n,&k,&m,&p);
	printf("%lld",(n%p*fpow(m,k-1)%p-fpow(m,k-2)*(k-1)%p*((1+m)*m/2%p)%p+p)%p);
	return 0;
}