题意
Sol
暴力找规律题
看到题,先考虑算每个节点会被算多少次。
一个节点要被算成(LCA) ,就是在左子树找一个节点,右子树找一个节点,匹配起来。
(这里的左子树和右子树都包括根节点)
最下面的叶子结点每个被算一次,然后往上推,上边的节点(第(i)层)每个被算(2^{1+2*(k-i)}-1)次。
减掉的那一次是重复算自己匹配自己的那一次。
发现同层的节点被算的次数是一样的,设(f_i)为第(i)层节点的编号的和
复杂度(O(Tk)) ,代码放下面。
然后发现如果我们中途不减那个一,答案的递推式就是
[ans_i=ans_{i-1}*4+2*f_i
]
要减去的答案是:前(i)层的节点的编号的和,也就是(sum_{f_i})。
用前缀和维护一下就好。
Code
(O(Tk))
#include<bits/stdc++.h>
#define P (998244353)
#define V (1000000)
#define N (1000010)
#define ll long long
using namespace std;
int T;
ll k,p[N],f[N];
inline ll read(){
ll w=0;
char ch=getchar();
while(ch>'9'||ch<'0') ch=getchar();
while(ch>='0'&&ch<='9'){
w=(w<<3)+(w<<1)+(ch^48);
ch=getchar();
}
return w;
}
int main(){
p[0]=1ll,f[1]=1ll;
for(int i=1;i<=V;i++) p[i]=(p[i-1]<<1)%P;
for(int i=2;i<=V;i++) f[i]=((f[i-1]<<2)%P+p[i-2])%P;
T=read();
while(T--){
ll ans=0;
k=read();
for(int j=1;j<=k;j++){
ans=(ans+(p[1+2*(k-j)]-1)*f[j]%P)%P;
}
printf("%lld
",ans);
}
return 0;
}
(O(T))
#include<bits/stdc++.h>
#define P (998244353)
#define V (1000000)
#define N (1000010)
#define ll long long
using namespace std;
int T;
ll k,p[N],f[N],sum[N],ans[N];
inline ll read(){
ll w=0;
char ch=getchar();
while(ch>'9'||ch<'0') ch=getchar();
while(ch>='0'&&ch<='9'){
w=(w<<3)+(w<<1)+(ch^48);
ch=getchar();
}
return w;
}
int main(){
p[0]=1ll,f[1]=1ll;
for(int i=1;i<=V;i++) p[i]=(p[i-1]<<1)%P;
for(int i=2;i<=V;i++) f[i]=((f[i-1]<<2)%P+p[i-2])%P;
for(int i=1;i<=V;i++) sum[i]=(sum[i-1]+f[i])%P;
for(int i=1;i<=V;i++) ans[i]=(ans[i-1]*4%P+2*f[i]%P)%P;
T=read();
while(T--){
k=read();
printf("%lld
",(ans[k]-sum[k]+P)%P);
}
return 0;
}
完结撒花❀
模数打成998244343调半天