BZOJ3142&&洛谷P3228 [HNOI2013]数列

毒瘤数学题

思路

我们考虑如何限定同类数列?
用涨幅相同限定
所以我们通过枚举每两天之间的涨幅就可以枚举出一类数列,这类数列有多少种呢?我们假设第i天到第i+1天的涨幅是s,第一天涨了s1,第二天涨s2,那么到最后我们可以通过调大第1天的价格,那么后面就一起变大了,所以因为有每天都不大于n这个限制,所以最大的那天应该是最后一天也就是第k天要小于等于n,不难发现将前几天的涨幅相加再加上第一天的价格就是最后一天的价格,所以第一天的价格满足最后一天不大于n有 n − ∑ i = 1 k − 1 s i n-\sum\limits_{i=1}^{k-1}s_i ni=1k1si种,所以我们可以列出答案的式子
a n s = ∑ s 1 = 1 m ∑ s 2 = 1 m . . . ∑ s k − 1 = 1 m ( n − ∑ i = 1 k − 1 s i ) ans=\sum\limits_{s1=1}^{m}\sum\limits_{s2=1}^{m}...\sum\limits_{s_{k-1}=1}^{m}(n-\sum\limits_{i=1}^{k-1}s_i) ans=s1=1ms2=1m...sk1=1m(ni=1k1si)
复杂度大概是 O ( m k ) O(m^k) O(mk),炸了!
看看能不能化简
a n s = n ∗ m k − 1 − ∑ s 1 = 1 m ∑ s 2 = 1 m . . . ∑ s k − 1 = 1 m ∑ i = 1 k − 1 s i ans=n*m^{k-1}-\sum\limits_{s1=1}^{m}\sum\limits_{s2=1}^{m}...\sum\limits_{s_{k-1}=1}^{m}\sum\limits_{i=1}^{k-1}s_i ans=nmk1s1=1ms2=1m...sk1=1mi=1k1si
a n s = n ∗ m k − 1 − ∑ i = 1 k − 1 ∑ s 1 = 1 m ∑ s 2 = 1 m . . . ∑ s k − 1 = 1 m s i ans=n*m^{k-1}-\sum\limits_{i=1}^{k-1}\sum\limits_{s1=1}^{m}\sum\limits_{s2=1}^{m}...\sum\limits_{s_{k-1}=1}^{m}s_i ans=nmk1i=1k1s1=1ms2=1m...sk1=1msi
a n s = n ∗ m k − 1 − ( k − 1 ) ∗ m k − 2 ∑ i = 1 m i ans=n*m^{k-1}-(k-1)*m^{k-2}\sum\limits_{i=1}^{m}i ans=nmk1(k1)mk2i=1mi
a n s = n ∗ m k − 1 − ( k − 1 ) ∗ m k − 2 ∗ m ∗ ( m + 1 ) 2 ans=n*m^{k-1}-(k-1)*m^{k-2}*\frac{m*(m+1)}{2} ans=nmk1(k1)mk22m(m+1)
然后就log可做啦!交给快速幂就好了

代码

//By AcerMo
#include
#include
#include
#include
#include
#define lli long long int
using namespace std;
lli n,k,m,p;
inline lli fpow(lli x,lli y)
{
	lli z=1;
	for (;y;x=(x*x)%p,y>>=1)
	if (y&1) z=(z*x)%p;
	return z;
}
signed main()
{
	cin>>n>>k>>m>>p;k--;n%=p;
	lli a1=(n*fpow(m,k))%p;
	lli a2=(k*fpow(m,k-1))%p;
	lli a3=(m*(m+1)/2)%p;
	cout<<(a1-(a2*a3)%p+p)%p;
	return 0;
}

你可能感兴趣的:(数论&&组合数学)