Always keep a |

luckydrawbox

园龄:4个月粉丝:1关注:2

P10128 「Daily OI Round 3」Xor Graph

Link\text{Link}

题意

给定 2n2^n 个点,编号为 12n1\sim 2^n,两个点 x,yx,y 之间有一条有向边当且仅当 y or x=x,y xor x=2k(k[0,n))y\ \text{or}\ x=x,y\ \text{xor}\ x=2^k(k\in[0,n))。令 fx,yf_{x,y}xx 点到 yy 点的不同路径数,求:

i=12nj=12nfi,j(ij)\sum_{i=1}^{2^n}\sum_{j=1}^{2^n}f_{i,j}(i\neq j)

答案对 998244353998244353 取模。

分析

把编号的二进制表示看成集合,那么对于一条边 xyx\rightarrow yyyxx 仅少了一个元素的子集。

显然点 2n2^n 是没用的,因为没有点 00。对于任意 y or x=xy\ \text{or}\ x=x,从 xx 走到 yy 相当于去掉 popcount(y xor x)\operatorname{popcount}(y\ \text{xor}\ x) 个元素,有 f(x,y)=popcount(y xor x)!f(x,y)=\operatorname{popcount}(y\ \text{xor}\ x)! 种路径,其他情况 f(x,y)=0f(x,y)=0

但这样计算仍然是 O(22n)O(2^{2n}) 的,考虑换个计算方式,把路径数相同的点对拿出来算,有

i=12nj=12nfi,j(ij)\sum_{i=1}^{2^n}\sum_{j=1}^{2^n}f_{i,j}(i\neq j) =y or x=xpopcount(y xor x)!=\sum_{y\ \text{or}\ x=x}\operatorname{popcount}(y\ \text{xor}\ x)! =i=1ni![popcount(y xor x)=i]=\sum_{i=1}^ni!\sum [\operatorname{popcount}(y\ \text{xor}\ x)=i]

[popcount(y xor x)=i]\sum [\operatorname{popcount}(y\ \text{xor}\ x)=i] 相当于 yyxxii 位不同的方案数,选出他们不同的位有 CniC_n^i 种方案,相同的位有 2ni12^{n-i}-1 种方案(yy 不能为 00),所以:

i=1ni![popcount(y xor x)=i]\sum_{i=1}^ni!\sum [\operatorname{popcount}(y\ \text{xor}\ x)=i] =i=1ni!Cni(2ni1)=\sum_{i=1}^ni!C_n^i(2^{n-i}-1) =i=1nn!(ni)!(2ni1)=\sum_{i=1}^n\frac{n!}{(n-i)!}(2^{n-i}-1) =n!i=0n12i1i!=n!\sum_{i=0}^{n-1}\frac{2^i-1}{i!}

后面那个和式显然是可以预处理前缀和的,于是这道题就解决了。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
long long read(){
	long long x=0,f=1;char ch=getchar();
	while(!isdigit(ch))
	{if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
void write(long long x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
const int N=1e7+10;
const ll mod=998244353;
int n;
int fac[N],inv[N],m2[N],sum[N];
ll qmi(ll a,ll b){
	ll ans=1;
	while(b){
		if(b&1)ans=ans*a%mod;
		a=a*a%mod;b>>=1;
	}
	return ans;
}
int main(){
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	fac[0]=inv[0]=m2[0]=1;
	for(int i=1;i<=N-2;i++)fac[i]=1ll*fac[i-1]*i%mod;
	inv[N-2]=qmi(fac[N-2],mod-2);
	for(int i=N-3;i>=1;i--)inv[i]=1ll*inv[i+1]*(i+1)%mod;
	for(int i=1;i<=N-2;i++)m2[i]=m2[i-1]*2%mod;
	sum[0]=0;
	for(int i=1;i<=N-2;i++){
		sum[i]=(sum[i-1]+1ll*(m2[i]-1+mod)%mod*inv[i]%mod)%mod;
	}
	int T=read();
	while(T--){
		n=read();
		write(1ll*sum[n-1]*fac[n]%mod);
		puts("");
	}
	return 0;
}

本文作者:luckydrawbox

本文链接:https://www.cnblogs.com/luckydrawbox/p/18526440

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   luckydrawbox  阅读(1)  评论(0编辑  收藏  举报  
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起