因为我太弱了不会推式子所以只能打表找规律加矩乘……
在m固定的情况下,以n为行以k为列打个表,发现在第i列,第一项在第(i-1)*m+1行,除了第一项以外每一项是他前一项+m^(i-1)
而第一项等于1~i-1列每一列的前m项的和
只要求出了第k列的第一项就能轻松求出第n行的值
我们设f[i]表示第i列的第一项,则f[1]=1,f[i]=m*f[i-1]+(m-1)*(m^(i-1))/2
矩乘加速一下即可
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
using namespace std;
#define MAXN 1010
#define MAXM 1010
#define INF 1000000000
#define MOD 1000000007
#define eps 1e-8
#define ll long long
ll p;
struct mat{
ll x[3][3];
mat(){
memset(x,0,sizeof(x));
}
friend mat operator *(mat x,mat y){
int i,j,k;
mat z;
for(i=1;i<=2;i++){
for(j=1;j<=2;j++){
for(k=1;k<=2;k++){
(z.x[i][j]+=x.x[i][k]*y.x[k][j])%=p;
}
}
}
return z;
}
};
ll n,k,m;
mat a,b,c;
ll mi(ll x,ll y){
ll re=1;
while(y){
if(y&1){
(re*=x)%=p;
}
(x*=x)%=p;
y>>=1;
}
return re;
}
int main(){
scanf("%lld%lld%lld%lld",&n,&k,&m,&p);
ll y=k-1;
a.x[1][1]=1;
a.x[1][2]=((m-1)*m/2)%p;
b.x[1][1]=b.x[2][2]=1;
c.x[1][1]=m%p;
c.x[2][1]=1;
c.x[2][2]=m%p;
while(y){
if(y&1){
b=b*c;
}
c=c*c;
y>>=1;
}
a=a*b;
printf("%lld\n",(a.x[1][1]+(n-(k-1)*m-1)%p*mi(m,k-1))%p);
return 0;
}
/*
*/