题解:P12046 [USTCPC 2025] 生成树!
Solution
高考数学做法。
考虑枚举所有和
显然需要满足:
给定一组
显然我们能写出
则有
暴力实现
考虑优化。如果你高考数学学明白了,就知道这种递推式带求和的数列求值可以多写几项然后抵消。
发现
具体咋化简的不展示了,可以得到:
特别的,
使用矩阵快速幂维护即可,复杂度
#include<bits/stdc++.h>
#define int long long
#define ffor(i,a,b) for(int i=(a);i<=(b);i++)
#define roff(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const int MAXN=100,MOD=1e9+7;
int n,k;
struct Mat {int v[3][3];}ori,mul;
Mat operator *(Mat A,Mat B) {
Mat C;
memset(C.v,0,sizeof(C.v));
ffor(i,0,2) ffor(j,0,2) ffor(k,0,2) C.v[i][k]=(C.v[i][k]+A.v[i][j]*B.v[j][k])%MOD;
return C;
}
Mat operator ^(Mat A,int p) {
Mat C;
memset(C.v,0,sizeof(C.v));
C.v[0][0]=C.v[1][1]=C.v[2][2]=1;
while(p) {
if(p&1) C=C*A;
A=A*A,p>>=1;
}
return C;
}
signed main() {
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>k;
int nk=k%MOD;
ori.v[0][0]=(4*nk+nk*nk)%MOD,ori.v[0][1]=nk,ori.v[0][2]=1;
mul.v[0][0]=nk+2,mul.v[0][1]=1,mul.v[0][2]=0;
mul.v[1][0]=-1,mul.v[1][1]=0,mul.v[1][2]=0;
mul.v[2][0]=2*nk%MOD,mul.v[2][1]=0,mul.v[2][2]=1;
if(n/k==1) cout<<nk;
else ori=ori*(mul^(n/k-2)),cout<<(ori.v[0][0]%MOD+MOD)%MOD;
return 0;
}