五分钟就推完了...
如果模数为质数还有一些简单的搞法,不是质数我好像只想到这一种简便一点的。
枚举每天与前一天的差值,第一天有 n-差值之和 的取法:
[sum_{x_1=1}^M sum_{x_2=1}^M ... sum_{x_{k-1}=1}^M (N-sum_{i=1}^{k-1}x_i)
]
[ans=M^{k-1}*N-sum_{x_1=1}^M sum_{x_2=1}^M ... sum_{x_{k-1}=1}^M(sum_{i=1}^{k-1} x_i)
]
令(g(i)=sum_{x_1=1}^M sum_{x_2=1}^M ... sum_{x_{i}=1}^M (sum_{j=1}^i x_i))
g是可以递推的。
[g(i)=sum_{x_1=1}^M ...sum_{x_{i-1}=1}^M sum_{x_{i}=1}^M (x_1+...+x_{i-1}+x_i)
]
[=sum_{x_1=1}^M ...sum_{x_{i-1}=1}^M(M*sum_{j=1}^{i-1}x_j+sum_{x_i=1}^M x_i)
]
[=M*sum_{x_1=1}^M ...sum_{x_{i-1}=1}^M (sum_{j=1}^{i-1}x_j) + M^{i-1}*frac{M*(M+1)}{2}
]
[=M*g(i-1)+M^{i-1}*frac{M*(M+1)}{2}
]
首先(g(1)=frac{M*(M+1)}{2},g(2)=2*M*frac{M*(M+1)}{2}),我们会去猜想(g(k)=k*M^{k-1}*frac{M*(M+1)}{2})。
然后就是简单的用数学归纳法证明了,假设我们知道了对于(i=k)时成立,有(g(k)=k*M^{k-1}*frac{M*(M+1)}{2}),那么(g(k+1)=M*g(k)+M^k*frac{M*(M+1)}{2}=k*M^k*frac{M*(M+1)}{2}+M^k*frac{M*(M+1)}{2}=(k+1)*M^k*frac{M*(M+1)}{2}),所以对于任意(iin N^{*}),猜想成立。
(当然也可以得到(frac{g(i)}{M^i}=frac{g(i-1)}{M^{i-1}}+frac{(M+1)}{2})就可以直接算通项了)
所以答案就是
[M^{k-1}*N-g(k-1)
]
[=M^{k-1}*N-(k-1)*M^{k-2}*frac{M*(M+1)}{2}
]
特判一下(k=1)的情况。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#define pl puts("lala")
#define cp cerr<<"lala"<<endl
#define fi first
#define se second
#define pb push_back
#define ln putchar('
')
using namespace std;
inline int read()
{
char ch=getchar();int g=1,re=0;
while(ch<'0'||ch>'9') {if(ch=='-')g=-1;ch=getchar();}
while(ch<='9'&&ch>='0') re=(re<<1)+(re<<3)+(ch^48),ch=getchar();
return re*g;
}
typedef long long ll;
typedef pair<int,int> pii;
int mod;
ll qpow(ll a,int n)
{
ll ans=1;
for(;n;n>>=1,a=a*a%mod) if(n&1) ans=ans*a%mod;
return ans;
}
ll n;
int m,k;
int main()
{
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);freopen("1.out","w",stdout);
#endif
scanf("%lld%d%d%d",&n,&k,&m,&mod);
n%=mod;
if(k==1) printf("%lld
",n);
else printf("%lld
",(qpow(m,k-1)*n%mod
-1ll*m*(m+1)/2%mod*(k-1)%mod*qpow(m,k-2)%mod+mod)%mod);
return 0;
}