「CF1713F」Lost Array

题目

点这里看题目。

有一个长度为 n 的非负整数序列 {ai}i=1n,以此生成一个 (n+1)×(n+1) 的非负整数矩阵 A​:

  • 对于 0in,有 Ai,0=0

  • 对于 1in,有 A0,i=ai

  • 对于 1i,jn,有 Ai,j=Ai1,jAi,j1​。

{bi=Ai,n}i=1n,现在给出 b,构造一组可以生成 ba,或报告无解。

所有数据满足 1n5×105,0bi230

分析

容易发现,ai 对于 bj 的贡献系数为 (ni+j1j1)

然而,在异或的含义下,我们关心的是 (ni+j1j1)mod2​,根据 Lucas 定理 (ni+j1j1)mod2​ 为 1​​ 当且仅当 (ni+j1)(j1)=j1​(用 xy​ 表示二进制下按位与)。

进一步地,我们尝试把 ni+j1​ 拆开。容易发现,上述条件等价于 (ni)(j1)=0,因为如果与非零,则 (ni)(j1) 的最低位不会被进位补齐,就会真的变成 0

找出 U=2log2n1​,我们把 U​ 当作“全集”,则所有 x(j1)=0x 必然是 U(j1) 的“子集”,这样我们就把 b 的限制变成了 na​ 的子集异或和的方程


a¯i={ani0i<n0niU​​​,也就是先反转再补零的结果。

如果 U=n1,那么我们就可以直接执行逆变换算出来 a¯,进而得到 a

然而实际情况没有这么好。设 Sx=yx=ya¯y​​,则我们得到的实际上是 SUn+1​​ 到 SU​​ 的准确值。但一个前缀的 S 的值是丢失的,所以光凭这些信息还不足以帮助我们快速地解出 a¯​​。

我们尝试再建立一点 a¯​ 和 S​ 之间的联系。不妨考虑朴素的容斥,我们知道 a¯y=xy=x(1)popcount(xy)Sx,而在按位异或的意义下 1 系数毫无作用,所以 a¯y=xy=xSx!也可以说 a¯S 互为子集异或和​!

我们马上注意到 a¯​ 在某些位置上为 0​,所以这又给我们新增了 Un+1​​​ 条关于 S​ 的方程。一共 U+1​ 条方程,正好可以解出 U+1​ 个变量。然而,未知量集中在前缀上,有效的方程集中在后缀上,我们还需要更多的处理。

不妨再把问题化简,我们消去所有已知的 S​ 的贡献,算出 Ty=0x<n,xy=0Sx​​。现在我们得到的就是纯粹的和前 nS 相关的问题了。结合二进制变换的一贯尿性,我们不妨考虑分治方法解决这个问题。

(B,L,R,q)​​​ 来表示“如果 T​​ 仅在前 B​​ 位做前缀和,已知 TRq+1TR​​,且 SL+qSR 都是 0,求出 SLSL+q1​​”。计算过程需要讨论一点情况:

  • 如果 q=RL+1,则可以直接逆变换算,这是边界。

  • 如果 q2B1​​,则 [L+2B1,R] 这一段因为全为 0 而没有贡献,可以直接递归到 (B1,L,L+R2,q) 计算​。

  • 否则,我们必须考虑交叉贡献。

    两边尝试一下,发现先计算区间 [L+2B1,R] 会容易一点。那么,在递归下去之前,我们需要消除 [L,L+2B11] 的影响

    r=q2B1。由于我们只知道 TRq+1TL+2B11 的信息,所以我们可以计算出仅在前 B1 位做前缀和时的 TRr+1TR。好巧不巧,根据对称性,区间 [L+2B1,R] 中也正好只有 r 个值未确定,递归下去形式已知,正好就是 (B1,L+2B1,R,r)

    解决完一边之后,我们可以相应地去掉 [L+2B1,R] 的贡献,从而得到仅在前 B1 位做前缀和时的 TLTL+2B11。所以,我们已经到边界了!

容易发现复杂度为 O(nlogn)​,因为每次递归大小折半且实质上只会走向单侧。

Remark.

不知道能写点什么,真正重要的内容全部用黑色加粗了。

不过我想说,tnnd 你谷题解区前三篇写的都是什么东西?正常人怎么会想到“先超集再子集”这种反常思路?当然很有可能是因为我是一个神必。总之看得我一头雾水。

一般来说,思路应当连贯,后来的多多少少要和已有的照应。思考的时候也可以注意一下,如果思路太发散就需要用纸笔辅助,避免忘了自己想过什么东西。

代码

#include <cstdio>
#include <vector>

#define rep( i, a, b ) for( int i = (a) ; i <= (b) ; i ++ )
#define per( i, a, b ) for( int i = (a) ; i >= (b) ; i -- )

const int MAXN = ( 1 << 20 ) + 5;

template<typename _T>
inline void Read( _T &x ) {
	x = 0; char s = getchar(); bool f = false;
	while( ! ( '0' <= s && s <= '9' ) ) { f = s == '-', s = getchar(); }
	while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar(); }
	if( f ) x = -x;
}

template<typename _T>
inline void Write( _T x ) {
	if( x < 0 ) putchar( '-' ), x = -x;
	if( 9 < x ) Write( x / 10 );
	putchar( x % 10 + '0' );
}

int su[MAXN];
int f[MAXN], tmp[MAXN];

int N, U, K;

inline void Conv( const int &b, int *coe ) {
	int n = 1 << b;
	for( int i = 0 ; i < b ; i ++ )
		for( int j = 0 ; j < n ; j ++ )
			if( j >> i & 1 ) coe[j] ^= coe[j ^ ( 1 << i )];
}

void Divide( const int &B, const int &L, const int &R, const int &len, int *val ) {
	if( ! len || B < 0 ) return ;
	int mid = ( L + R ) >> 1;
	if( len == R - L + 1 ) {
		rep( i, 0, len - 1 ) tmp[i] = val[i];
		Conv( B, tmp );
		rep( i, 0, len - 1 ) su[i + L] = tmp[i];
	} else if( len <= mid - L + 1 ) 
		Divide( B - 1, L, mid, len, val );
	else {
		std :: vector<int> old( val, val + len );
		int rsd = len - ( R - mid ), hlf = 1 << ( B - 1 );
		rep( i, 0, rsd - 1 ) val[i + hlf] ^= val[i];
		Divide( B - 1, mid + 1, R, rsd, val + hlf );
		rep( i, 0, hlf - 1 ) 
			tmp[i] = i < rsd ? su[i + mid + 1] : 0;
		Conv( B - 1, tmp );
		rep( i, 0, hlf - 1 ) tmp[i] ^= old[i + rsd];
		rep( i, 0, hlf - 1 ) val[i] = tmp[i];
		Divide( B - 1, L, mid, hlf, val );
	}
}

int main() {
	Read( N );
	for( U = 1, K = 0 ; U < N ; U <<= 1, K ++ );
	rep( i, 0, N - 1 ) {
		int b; Read( b );
		su[( U - 1 ) ^ i] = b;
	}
	rep( i, 0, U - 1 ) f[i] = i <= U - 1 - N ? 0 : su[i];
	Conv( K, f );
	if( U == N ) {
		rep( i, 1, N )
			Write( f[N - i] ), putchar( " \n"[i == N] );
		return 0;
	}
	Divide( K, 0, U - 1, U - N, f + N );
	Conv( K, su );
	rep( i, 1, N ) Write( su[N - i] ), putchar( " \n"[i == N] );
	return 0;
}
posted @   crashed  阅读(53)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
历史上的今天:
2021-11-15 「牛客」牛半仙的妹子序列
2021-11-15 「CF1119G」Get Ready for the Battle
2020-11-15 [CSP2020]函数调用
点击右上角即可分享
微信分享提示