2 条题解

  • 3
    @ 2025-5-27 8:57:36

    因为我们发现第 aia_i 号位置上的人只对 a2×ia_{2\times i} 号位置的人和 a2×i+1a_{2\times i+1} 的位置上的人有影响,这很像二叉树

    所以说我们可以考虑建树,使得每个节点都小于自己的儿子节点即可

    然后我们考虑对每一个节点来看有多少种可能性的填法,最后乘起来即可

    首先根节点一定要填 11

    然后我们考虑左子树,左子树的所有数的选择方案是 Cn1sz2C_{n-1}^{sz_2} ,也就是说在剩下的 n1n-1 个数里面,选择 22 号节点的子树大小个数的方案数

    然后依次往下递归,对每一个左子树的节点附上一个这样的值看,最后乘起来就行了

    #include<iostream>
    #include<cstdio>
    #define int long long
    using namespace std;
    bool Test_MLE_start;
    const int N=2e6+10;
    int T=1,n,mod,ans=1;
    int fac[N],inv[N],ret[N],sz[N],fa[N];
    inline int reads(){
    	char c=getchar();
    	int sum=0,f=1;
    	while(!isdigit(c)){
    		if(c=='-') f=-1;
    		c=getchar();
    	}
    	while(isdigit(c)){
    		sum=(sum<<3)+(sum<<1)+(c^'0');
    		c=getchar();
    	}
    	return sum*f;
    }
    inline void files(){
    	freopen("std.in","r",stdin);
    	freopen("std.out","w",stdout);
    }
    inline void clr(){
    //	Don't forget!
    
    }
    int C(int n,int m){
    	if(n<m) return 0;
    	return fac[n]*inv[m]%mod*inv[n-m]%mod;
    }
    int Lucas(int n,int m){
    	if(!m) return 1;
    	return C(n%mod,m%mod)*Lucas(n/mod,m/mod)%mod;
    }
    void dfs(int idx){
    	if(idx>n) return;
    	dfs(2*idx),dfs(2*idx+1);
    	fa[2*idx]=fa[2*idx+1]=idx;
    	sz[idx]+=sz[2*idx]+sz[2*idx+1]+1;
    }
    void dfs2(int idx){
    	if(idx>n) return;
    	if(idx%2==0){
    		ret[idx]=Lucas(sz[fa[idx]]-1,sz[idx]);
    //		cout<<idx<<":"<<fa[idx]<<" "<<sz[fa[idx]]-1<<" "<<sz[idx]<<"\n";
    	}
    	dfs2(idx*2),dfs2(idx*2+1);
    }
    bool Test_MLE_end;
    signed main(){
    //	printf("%lf Mb\n",(&Test_MLE_end-&Test_MLE_start-1)/1024.0/1024.0);
    //	files();
    //	T=reads();
    	while(T--){
    		clr();
    		n=reads(),mod=reads();
    		inv[0]=inv[1]=fac[0]=fac[1]=1;
    		for(int i=2;i<=N-10;i++) fac[i]=fac[i-1]*i%mod,inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    		for(int i=1;i<=N-10;i++) inv[i]=inv[i]*inv[i-1]%mod;
    		for(int i=1;i<=n;i++) ret[i]=1;
    		dfs(1);
    		dfs2(1);
    		for(int i=1;i<=n;i++) ans=(ans*ret[i])%mod;
    		printf("%lld\n",ans);
    	}
    	return 0;
    }
    
    
    
    • @ 2025-5-27 11:03:05

      这个代码写的太史了

      在 dfs() 中,会越界

      给一个更好的代码

      #include<iostream>
      #include<cstdio>
      
      #define lc (x<<1)
      #define rc (x<<1|1)
      
      using namespace std;
      
      long long n,mod;
      
      inline long long ksm(long long a,long long b){
      	long long res=1;
      	while (b){
      		if (b&1) res=res*a%mod;
      		a=a*a%mod;
      		b>>=1;
      	}
      	return res;
      }
      long long fac[1000006],inv[1000006];
      inline void init(){
      	long long N=min(n,mod-1);
      	fac[0]=inv[0]=1;
      	for (int i=1;i<=N;i++){
      		fac[i]=fac[i-1]*i%mod;
      	}
      	inv[N]=ksm(fac[N],mod-2);
      	for (int i=N-1;i>=1;i--){
      		inv[i]=inv[i+1]*(i+1)%mod;
      	}
      }
      inline long long C(long long n,long long m){
      	if (n<m) return 0;
      	return fac[n]*inv[m]%mod*inv[n-m]%mod; 
      }
      inline long long Lucas(long long n,long long m){
      	if (!m) return 1;
      	return Lucas(n/mod,m/mod)*C(n%mod,m%mod)%mod;
      }
      
      long long fa[1000006],siz[1000006],ret[1000006],ans=1;
      void dfs1(long long x){
      	if (x>n) return;
      	dfs1(lc); dfs1(rc);
      	if (lc<=n) {fa[lc]=x; siz[x]+=siz[lc];}
      	if (rc<=n) {fa[rc]=x; siz[x]+=siz[rc];}
      	++siz[x];
      }
      void dfs2(long long x){
      	if (x>n) return;
      	if (!(x&1)) ret[x]=Lucas(siz[fa[x]]-1, siz[x]);
      	dfs2(lc); dfs2(rc);
      }
      
      int main(){
      	scanf("%lld%lld",&n,&mod);
      	for (int i=1;i<=n;i++) ret[i]=1;
      	init(); dfs1(1); dfs2(1);
      	for (int i=1;i<=n;i++) ans=ans*ret[i]%mod;
      	printf("%lld",ans);
      	return 0;
      }
      
  • 0
    @ 2026-6-17 9:02:52

    容易发现二叉树。

    因为答案只和相对大小有关,所以对于一个子树,给它分配那些点的方案数都是相同的,于是自底向上dp方案数。

    #include<bits/stdc++.h>
    #define int long long
    #define lc (x<<1)
    #define rc (x<<1|1)
    using namespace std;
    const int N=1e6+17;
    int mod,siz[N],dep[N],mxd;
    int mul[N],inv[N];
    int qpow(int a,int b){
    	int res=1;
    	while(b){
    		if(b&1) res=res*a%mod;
    		a=a*a%mod;b=b>>1ll;
    	}return res;
    }
    int C(int n,int m){
    	if(n<m) return 0;
    	int res=mul[n]*inv[m]%mod;
    	res=res*inv[n-m]%mod;return res;
    }
    int Lucas(int n,int m){
    	if(n<mod&&m<mod) return C(n,m);
    	return (int)(C(n%mod,m%mod)*Lucas(n/mod,m/mod)%mod);
    }
    int n;
    void dfs1(int x){
    	siz[x]=1;
    	if(lc<=n){dfs1(lc);siz[x]+=siz[lc];}
    	if(rc<=n){dfs1(rc);siz[x]+=siz[rc];}
    }
    int dfs(int x){
    	if(lc>n||rc>n) return 1;//
    	int res=dfs(lc)*dfs(rc)%mod;
    	res=res*Lucas(siz[x]-1,siz[lc])%mod;
    	return res;
    }
    signed main(){
    	cin >> n >> mod;mul[0]=1;inv[0]=1;
    	for(int i=1;i<=N-1;i++){
    		mul[i]=mul[i-1]*i%mod;
    		inv[i]=qpow(mul[i],mod-2);
    	}dfs1(1);int ans=dfs(1);
    	cout << ans << '\n';
    	
    	return 0;
    }
    
    • 1

    信息

    ID
    235
    时间
    1000ms
    内存
    256MiB
    难度
    6
    标签
    (无)
    递交数
    25
    已通过
    11
    上传者