首页 > 其他分享 >题解:P10104 [GDKOI2023 提高组] 异或图

题解:P10104 [GDKOI2023 提高组] 异或图

时间:2024-09-26 10:15:16浏览次数:1  
标签:le int 题解 P10104 容斥 异或 集合 mod 关键点

\(\text{Link}\)

本题属于集合划分容斥,更多关于集合划分容斥的信息可观看 详细揭秘:集合划分容斥的容斥系数

题意

给定一个 \(n\) 个点 \(m\) 条边的图以及一个长为 \(n\) 的序列 \(a_{1\dots n}\),有一常数 \(C\),你需要求出有多少序列 \(b_{1\dots n}\) 满足 \(0\le b_i\le a_i\),\(\forall (u,v)\in E,b_u\ne b_v\),\(\text{xor}_{i=1}^nb_i=C\)。

\(n\le 15\)。

思路

考虑 \(m=0\) 怎么做,从高至低枚举第一个不全顶到上界的位 \(d\),则低 \(d-1\) 位只需要一个在第 \(d\) 位不顶到上界的数进行调整,其余数任选即可。

令等价类为相等的数的集合,则令集合幂级数 \([x^S]F(x)\) 等于 \(1\) 当且仅当 \(S\) 内点在图上为独立集。容斥系数 \(H(x)=\ln (F(x)+1)\) 可以直接求出。

考虑一个状态的答案,我们只关注每个等价类内部的最小值。每个大小为偶数的等价类均可随便取,大小为奇数的等价类的最小值(称为关键点)构成 \(m=0\) 的子问题。

设 \(f_{S,T}\) 表示当前已经考虑了 \(S\) 内的点,其中关键点的集合为 \(T\) 的方案数,时间复杂度为 \(O(4^n)\)。

此时记录了大量无用信息,我们将 \(a\) 从小到大排序,逐个尝试加入关键点。设当前加入到 \(i\),则 \([1,i)\) 的点已经必然在考虑的点集中,只需要记录它们是否在关键点集中;\([i,n]\) 的点必然不在当前关键点集中,只需要记录它们是否在已考虑点集中。这样状态数就减小至 \(2^n\),再加上枚举子集,时间复杂度为 \(O(3^nn+2^n(m+n\log V))\)。

参考代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff
	
}
const int S=1<<15,N=15+2,M=N*N,mod=998244353;
namespace Init{
    inline int add(int x,int y){
        return x+y>=mod?x+y-mod:x+y;
    }
    inline int dec(int x,int y){
        return x>=y?x-y:x-y+mod;
    }
	int pc[S],inv[N],fac[N];
	inline void Prefix(int n){
		int m=__lg(n);
		for(int i=0;i<n;i++)
			pc[i]=pc[i/2]+(i&1);
		inv[1]=1;
		for(int i=2;i<=m;i++)
			inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
		fac[0]=1;
		for(int i=1;i<=m;i++)
			fac[i]=1ll*fac[i-1]*i%mod;
	}
}
using namespace Init;
namespace Poly{
	int n,m;
	inline void init(int N){
		n=N,m=__lg(n);
	}
	inline void FWT(int *c){
		for(int i=0;i<m;i++)
			for(int j=0;j<n;j++)
                if(j>>i&1)
                    c[j]=add(c[j],c[j^(1<<i)]);
	}
	inline void IFWT(int *c){
		for(int i=0;i<m;i++)
			for(int j=n-1;j>=0;j--)
                if(j>>i&1)
                    c[j]=dec(c[j],c[j^(1<<i)]);
	}
	int F[N][S],G[N][S],H[N][S];
	inline void mul(int *a,int *b,int *c){
		for(int i=0;i<m;i++)
			for(int j=0;j<n;j++)
				F[i][j]=G[i][j]=H[i][j]=0;
		for(int i=0;i<n;i++)
			F[pc[i]][i]=a[i],G[pc[i]][i]=b[i];
		for(int i=0;i<=m;i++)
			FWT(F[i]),FWT(G[i]);
		for(int k=0;k<=m;k++){ 
			for(int i=0;i<=k;i++)
				for(int j=0;j<n;j++)
					H[k][j]=(H[k][j]+1ll*F[i][j]*G[k-i][j])%mod;
			IFWT(H[k]);
		}
		for(int i=0;i<n;i++)
			c[i]=H[pc[i]][i];
	}
	inline void ln(int *a,int *b){
		for(int i=0;i<m;i++)
			for(int j=0;j<n;j++)
				F[i][j]=G[i][j]=0;
		for(int i=0;i<n;i++)
			F[pc[i]][i]=a[i];
		for(int i=0;i<=m;i++)
			FWT(F[i]);
		for(int p=0;p<n;p++)
			for(int i=1;i<=m;i++){
				int s=0;
				for(int j=1;j<i;j++)
					s=(s+1ll*(i-j)*F[j][p]%mod*G[i-j][p])%mod;
				s=dec(1ll*i*F[i][p]%mod,s);
				G[i][p]=1ll*s*inv[i]%mod;
			}
		for(int i=0;i<=m;i++)
			IFWT(G[i]);
		for(int i=0;i<n;i++)
			b[i]=G[pc[i]][i];
	}
}
using Poly::init;
using Poly::ln;
int n,m,p[N],r[N],F[S],H[S],dp[N][2][2],f[S],g[S];
ll a[N],b[N],C;
struct node{
	int u,v;
}e[M];
inline int solve(int s){
	int ct=0;
	for(int i=0;i<n;i++)
		if(s>>i&1)
			b[++ct]=a[p[i]];
	int ans=0,fl=0;
	for(int d=59;d>=0;d--){
		ll w=1ll<<d;
		int c=0,v=C>>d&1,wc=w%mod;
		dp[0][0][0]=1;
		for(int i=1;i<=ct;i++){
			if(b[i]&w){
				b[i]^=w,c++;
				int v=(b[i]+1)%mod;
				dp[i][0][0]=1ll*dp[i-1][0][1]*v%mod;
				dp[i][0][1]=1ll*dp[i-1][0][0]*v%mod;
				dp[i][1][0]=(1ll*dp[i-1][1][1]*v+1ll*dp[i-1][1][0]*wc+dp[i-1][0][0])%mod;
				dp[i][1][1]=(1ll*dp[i-1][1][0]*v+1ll*dp[i-1][1][1]*wc+dp[i-1][0][1])%mod;
			}else{
				int v=(b[i]+1)%mod;
				dp[i][0][0]=1ll*dp[i-1][0][0]*v%mod;
				dp[i][0][1]=1ll*dp[i-1][0][1]*v%mod;
				dp[i][1][0]=1ll*dp[i-1][1][0]*v%mod;
				dp[i][1][1]=1ll*dp[i-1][1][1]*v%mod;
			}
		}
		ans=(ans+dp[ct][1][v])%mod;
		if((c&1)!=v){ fl=1;break; }
	}
	if(!fl) ans++;
	return ans;
}
inline bool cmp(int i,int j){
	return a[i]<a[j];
}
inline int get(int s,int l,int r){
	return s&(((1<<r+1)-1)^((1<<l)-1));
}
int main(){
	n=read(),m=read(),C=read();
	for(int i=0;i<n;i++)
		a[i]=read(),p[i]=i;
	sort(p,p+n,cmp);
	for(int i=0;i<n;i++)
		r[p[i]]=i;
	for(int i=1;i<=m;i++)
		e[i].u=r[read()-1],e[i].v=r[read()-1];
	int u=1<<n;
	Prefix(u),init(u);
	for(int s=0;s<u;s++){
		bool fl=1;
		for(int i=1;i<=m;i++)
			if((s>>e[i].u&1)&&(s>>e[i].v&1)){
				fl=0;
				break;
			}
		F[s]=fl;
	}
	ln(F,H);
	f[0]=1;
	for(int i=0;i<n;i++){
		for(int s=0;s<u;s++){
			int v=f[s];
			if(!v) continue;
			int cur=((1<<i)-1)|get(s,i,n-1);
			if(cur>>i&1){
				int t=s^(1<<i);
				g[t]=add(g[t],v);
				continue;
			}
			for(int T=(u-1)^cur^(1<<i),t=T;;t=(t-1)&T){
				if(pc[t]&1) g[s|t]=(g[s|t]+1ll*v*H[t|(1<<i)]%mod*(a[p[i]]%mod+1))%mod;
				else g[s|t|(1<<i)]=(g[s|t|(1<<i)]+1ll*v*H[t|(1<<i)])%mod;
				if(!t) break;
			}
		}
		for(int s=0;s<u;s++)
			f[s]=g[s],g[s]=0;
	}
	int ans=0;
	for(int s=0;s<u;s++)
		ans=(ans+1ll*f[s]*solve(s))%mod;
	write(ans);
	flush();
}

标签:le,int,题解,P10104,容斥,异或,集合,mod,关键点
From: https://www.cnblogs.com/cyffff/p/18432906

相关文章

  • 题解:P10198 Infinite Adventure P
    \(\text{Link}\)题意给定\(n\)个数组\(c_{i,0\dotst_i-1}\),其中\(t_i\)为\(2\)的幂。有\(q\)次询问,每次询问给出三个参数\(x,T,\Delta\),接下来会执行\(\Delta\)次\(x\getsc_{x,T\bmodt_x},T\getsT+1\),求出最终的\(x\)。\(n,\sumt\le10^5\),\(q\le5\time......
  • 题解:P10998 Tuple+
    \(\text{Link}\)有意思,记录一下。题意给出\(m\)个互不相同的无序三元组\((u,v,w)\),求有多少无序四元组\((a,b,c,d)\)使得三元组\((a,b,c),(a,b,d),(a,c,d),(b,c,d)\)均存在。\(m\le3\times10^5\)。Bonus:\(m\le2\times10^6\)。题解回忆无向图三元环计数的做法,使......
  • 题解:P10590 磁力块
    \(\text{Link}\)来自传奇讨论区大神@年年有年的\(O(n\logn)\)做法!题意有\(n+1\)块磁铁\(0\simn\),每个磁铁都有四个属性\((d_i,m_i,p_i,r_i)\),如果你拥有了磁铁\(i\),那么你就能吸引并拥有所有满足\(d_j\ler_i,m_j\lep_i\)的磁铁\(j\),初始你只拥有磁铁\(0\),求最......
  • 题解:CF1799F Halve or Subtract
    \(\text{Link}\)介绍一下一种高维wqs的方法。此方法来自@YeahPotato的专栏严谨的WQS二分方法。题意给定一个长为\(n\)的序列\(v_{1\dotsn}\),三个常数\(d,a,b\)。你可以执行若干次以下两种操作:选择\(1\lei\len\),令\(v_i\gets\lceil\frac{v_i}{2}\rceil\)。......
  • 勇攀山丘小队(翻越篇)1——题解
    前言胸有丘壑,气吞山河。正片A题:考虑使用DP,由于题目给了2个a不能在一起的限制,所以每次接上一个a都要考虑一下前面的一个状态是否也是a。于是就可以使用\(f,g\)数组,\(f_i\)表示第\(i\)个字母是a的合法情况有多少,\(g_i\)表示第\(i\)个字母是b或c的合法......
  • P8907 [USACO22DEC] Making Friends P 题解
    P8907[USACO22DEC]MakingFriendsP题解我们考虑维护每个\(i\),在\(i\)的后面有多少个点和它有朋友关系。初步的想法是每删掉一个人就给集合里所有的点连边。但是我们发现这样太不优了,有很多边会重复连很多次。优化的想法是对于\(i\),删去之后连的边就成了一个完全图,于是......
  • [GYM103119K][2020 ICPC Asia Macau] Candy Ads 题解
    题意简述有\(n\)个广告,每个广告在一个时间段内占据二维平面的矩形,\(m\)个约束表示两个广告至少有一个要被选择,选择若干广告,满足所有约束且同时刻不能有重叠的广告。Kosaraju算法流程在正图上跑一遍DFS,给每个位置打上时间戳从时间戳大到小枚举点,在反图上跑DFS,这个时候对......
  • 题解 洛谷P3398 仓鼠找 sugar
    原题链接:P3398仓鼠找sugar题解里大部分都是用的lca,然而我看不懂那些关于lca的性质是怎么证明出来的。不过这题可以直接用树链剖分来写,把模板套上去就好了。题意为查找两条路径是否存在公共点,我们只需要把其中一条路径上的点都赋值为1,然后查询另一条路径上的点的总和,如果总和......
  • [ARC062F] AtCoDeerくんとグラフ色塗り 题解
    思路对于一个点双,我们可以发现:假如它是一个简单环,那么它只能旋转这一个环,我们可以使用polya定理计算。假如它是多个环的组成,那么它的颜色可以随意调动,任何的情况都可以得到,那么假如说有\(m\)条边,方案数则为\(\binom{m+k-1}{k-1}\),我们只考虑每一种颜色的出现次数。对于......
  • 题解 QOJ5034【>.<】/ BC2401D【可爱路径】
    必可赛前公益众筹赛第一试Dhttps://qoj.ac/problem/5034,2022-2023集训队互测Round6(Nov12,2022)题目描述这原本是一道简单的最短路问题,但是由于种种地域文化,宗教信仰以及政治因素,原来一些或许可以行走的路径不能通行了。我们定义禁止路径为连续的经过一些特定的点的......