专栏文章
T666848 闪现树 题解
个人记录参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @minwsuz7
- 此快照首次捕获于
- 2025/12/02 09:38 3 个月前
- 此快照最后确认于
- 2025/12/02 09:38 3 个月前
出的很好的计数题。
我们的最初想法是,发现只会向下延伸 或 个儿子。设 表示第 层有几个节点 将要(在下一层) 向下延伸 个,有几个 将要(在下一层) 向下延伸 个。
那么 且 。
发现当 时, 会多算一些节点,因为有些不能额外延伸了(它这个点的“延伸路径”已经等于 了,不能再往下扩了)。
考察这些“不能延伸”的节点的性质,发现:
对于一个往下延伸 个儿子的点,我们发现它一定来自于如下路径: 阶闪现树的左右叶子 阶闪现树的中叶子 阶闪现树的左右叶子+...注意这里等价于用一个类似 的,长度为 的序列描述它的 (就是 )。我们整体把它 ,最后加回来,中间用组合意义计算即可。最后,发现 层的“将要(在下一层) 不能向下延伸 个儿子”的冗余节点的个数为 。
然后每一层节点个数就是 ,注意在减去冗余节点之前计算。实现时注意取模。
CPP#include<bits/stdc++.h>
#define _for(i,x,y) for(int i=x;i<=y;++i)
#define _forp(i,x,y,z) for(int i=x;i<=y;i+=z)
#define _rep(i,x,y) for(int i=x;i<y;++i)
using namespace std;
const int N=10000005,mod=998244353;
int ans=0,f[N],fac[N],inv[N],pow4[N],g[N],n,l,r;
int qpow(int x,int y){
if(y<0) return 0;
int ans=1;
x%=mod;
while(y){
if(y&1) ans=1ll*ans*x%mod;
x=1ll*x*x%mod;
y>>=1;
}
return ans;
}
int C(int n,int m){
if(n==m) return 1;
if(m==0) return 1;
if(n<m) return 0;
if(m<0) return 0;
return 1ll*fac[n]*inv[n-m]%mod*inv[m]%mod;
}
void build(){
fac[0]=pow4[0]=1;
_for(i,1,N-5) fac[i]=1ll*fac[i-1]*i%mod,pow4[i]=1ll*pow4[i-1]*4ll%mod;;
inv[N-5]=qpow(fac[N-5],mod-2);
for(int i=N-6;i;--i) inv[i]=1ll*inv[i+1]*(i+1ll)%mod ;
}
void solve(){
cin>>n>>l>>r;
build();
f[0]=1;
g[0]=0;
_for(i,1,min(N-5,2*n)){
g[i]=f[i-1]*2%mod;
f[i]=(g[i-1]*2%mod+f[i-1])%mod;
if(l<=i&&i<=r){
ans^=(f[i]+g[i])%mod;
}
if(i>=n) f[i]-=(1ll*pow4[i-n]*C(n,i-n))%mod,f[i]+=mod,f[i]%=mod;
}
cout<<ans<<'\n';
}
signed main(){
// freopen("test.in","r",stdin);
// freopen("test.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);
int T=1;
// cin>>T;
while(T--){
solve();
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...