【2022省选模拟】[ZROI] 神必的集合——线性基、数位DP

原题不提供链接

题目描述

在这里插入图片描述
在这里插入图片描述

题解

通过初步分析发现,一个合法集合 S S S 与一个 [ 0 , 2 n ) [0,2^n) [0,2n) 的最简线性基一一对应。

最简线性基是指对于 ∀ i > j \forall i>j i>j,若 b t i > 0 且 b t j > 0 bt_i>0且bt_j>0 bti>0btj>0,则 b t i bt_i bti 的二进制第 j j j 位为0,相当于 b t i bt_i bti 不能通过异或 b t j bt_j btj 变得更小。

现在考虑 m = 0 m=0 m=0 的情况,我们要怎么统计这样的线性基的个数。考虑从低位到高位确定这个线性基,我们设 p r i = ∑ j = 0 i − 1 [ b t j > 0 ] pr_i=\sum_{j=0}^{i-1}[bt_j>0] pri=j=0i1[btj>0] 表示线性基中第 i i i 位以前的数的数量,那么如果 b t i > 0 bt_i>0 bti>0 的话, b t i bt_i bti 上有 p r i pr_i pri 位强制为0。对于剩下的 i − p r i i-pr_i ipri 位,显然是可以任取的,所以 b t i bt_i bti 2 i − p r i 2^{i-pr_i} 2ipri 种取值。可以发现每一位上的取值方案数只与 p r i pr_i pri 有关,所以我们可以设 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示确定了线性基前面 0 ∼ i 0\sim i 0i 位, p r i = j pr_i=j pri=j 时的方案数,对 b t i > 0 bt_i>0 bti>0 b t i = 0 bt_i=0 bti=0 两种情况分别转移即可。

然后考虑限制条件,对于一个限制 x i , y i x_i,y_i xi,yi,它相当于包含两个条件:

  1. y i y_i yi 可以被线性基表示出来(即包含在集合 S S S 中);
  2. 线性基能够表示出来的数中, < y i <y_i <yi 的有 x i − 1 x_i-1 xi1 个。

对于第一个条件,我们可以先把所有 y i y_i yi 插入一个空线性基里,那么我们答案所求的线性基相当于是把这个线性基中若干个 b t i = 0 bt_i=0 bti=0 的位置给填上。

对于第二个条件,不妨先考虑一下对于一个确定的线性基,我们怎么统计 < y i <y_i <yi 的数的个数。我们可以用数位DP的方式,从高位到低位考虑,如果当前枚举的数在 > i >i >i 的位上是抵着上界 y i y_i yi 的,而 y i y_i yi 的第 i i i 位为1并且 b t i > 0 bt_i>0 bti>0,那么我们可以使得枚举的数的第 i i i 位为0。这时脱离了上界,后面 i i i 位可以任取,所以要给答案加上 2 p r i 2^{pr_i} 2pri

所以这个数位DP告诉我们:所有线性基上有数并且 y i y_i yi 上这一位是1的位置 j j j 可以贡献 2 p r j 2^{pr_j} 2prj,而你需要让贡献和等于 x i − 1 x_i-1 xi1

容易发现这样统计下来答案一定是 ∑ i 2 v i \sum_i2^{v_i} i2vi 形式的,其中 v i v_i vi 互不相同。巧的是,对于任意一个非负整数,这样的分解方式只有唯一一种。所以当我们求出 x i − 1 x_i-1 xi1 的分解 x i − 1 = ∑ i 2 v i x_i-1=\sum_i2^{v_i} xi1=i2vi 时,限制转化为对于线性基中从低位到高位第 v i + 1 v_i+1 vi+1 个非零位置 s i s_i si p r s i = v i 且 b t s i > 0 pr_{s_i}=v_i且bt_{s_i}>0 prsi=vibtsi>0),满足 s i ∈ { x ∣ y i 的 第 x 位 为 1 } s_i\in\{x|y_i的第x位为1\} si{xyix1},同时对于所有 p r j ∉ { v i } 且 b t j > 0 pr_j\notin \{v_i\}且bt_j>0 prj/{vi}btj>0 的位置 j j j,满足 j ∈ { x ∣ y i 的 第 x 位 为 0 } j\in\{x|y_i的第x位为0\} j{xyix0}

这样我们就可以预处理出从低位到高位填的每一个数的位置的限制,再加上有的位已经强制填了数,我们可以用 m = 0 m=0 m=0 情况中提到的DP来转移了。

注意到DP转移只与哪些位置是否填了数有关,所以一开始把 y i y_i yi 插入线性基的时候不需要用高斯-约当消元把它消成最简线性基。

代码

核心的DP部分应该写得比较清楚

#include<bits/stdc++.h>//JZM yyds!!
#define ll long long
#define uns unsigned
#define IF (it->first)
#define IS (it->second)
#define END putchar('\n')
using namespace std;
const int MAXN=205;
const ll INF=1e18;
inline ll read(){
	ll x=0;bool f=1;char s=getchar();
	while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();}
	while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();
	return f?x:-x;
}
int ptf[50],lpt;
inline void print(ll x,char c='\n'){
	if(x<0)putchar('-'),x=-x;
	ptf[lpt=1]=x%10;
	while(x>9)x/=10,ptf[++lpt]=x%10;
	while(lpt)putchar(ptf[lpt--]^48);
	if(c>0)putchar(c);
}
inline ll lowbit(ll x){return x&-x;}

const ll MOD=998244353;
inline void ad(ll&a,ll b){
	a+=b;if(a>=MOD)a-=MOD;
}
int n,m;
ll rk[MAXN],a[MAXN];
ll bt[65],dp[65][65],can[65];
inline void ins(ll x){
	for(int i=n-1;i>=0;i--)if((x>>i)&1){
		if(!bt[i])bt[i]=x,i=0;
		else x^=bt[i];
	}
}
inline ll solve(){
	memset(bt,0,sizeof(bt));
	memset(dp,0,sizeof(dp));
	for(int i=0;i<=n;i++)can[i]=(1ll<<n)-1;
	for(int i=1;i<=m;i++)ins(a[i]);
	int mx=0;
	for(int id=1;id<=m;id++){
		ll ca=a[id],d=rk[id];
		for(int i=0;i<n;i++){
			if((d>>i)&1)can[i+1]&=ca,mx=max(mx,i+1);
			else can[i+1]&=(can[0]^ca);
		}
	}
	if(!bt[0])dp[0][0]=1;
	if(can[1]&1)dp[0][1]=1;
	for(int i=1;i<n;i++){
		if(bt[i]){//已经填了数
			for(int j=1;j<=i+1;j++)if((can[j]>>i)&1)
				ad(dp[i][j],dp[i-1][j-1]);
		}else{
			for(int j=1;j<=i+1;j++)if((can[j]>>i)&1)
				ad(dp[i][j],(1ll<<(i+1-j))%MOD*dp[i-1][j-1]%MOD);
			for(int j=0;j<=i;j++)ad(dp[i][j],dp[i-1][j]);
		}
	}
	ll res=0;
	for(int i=mx;i<=n;i++)ad(res,dp[n-1][i]);
	return res;
}
signed main()
{
	freopen("set.in","r",stdin);
	freopen("set.out","w",stdout);
	n=read(),m=read();
	for(int i=1;i<=m;i++)rk[i]=read()-1,a[i]=read();
	print(solve());
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值