2023.11.10

发布时间 2023-11-10 15:52:53作者: SError

A

一棵 \(n\) 个点的树,每个节点有两个权值 \(a,b\),初始均为 \(0\)

在每个时刻,可以选择至多一个节点 \(x\)(或者不选),操作 \(b_x\leftarrow b_x\oplus 1\)。对于在当前时刻所有 \(b\) 值为 \(1\) 的节点 \(x\),令 \(a_x\leftarrow a_x\oplus 1\),此后,令 \(b_x\leftarrow b_x\oplus 1\)\(b_{fa_x}\leftarrow b_{fa_x}\oplus 1\)(当 \(fa_x\) 存在时)。

给出 \(\{a_n\}\) 的目标状态,问能够达到目标的最小时刻。

\(1\le n\le 16\),保证 \(fa_i<i\)


B

\(n\) 个点,给出 \(m\) 条信息,每个形如四元组 \((u_j,v_j,L_j,R_j)\)

对于条件 \(j\),选择一个 \(t\in[L_j,R_j]\),将条件按时间排序之后,若 \(u_j\)\(v_j\) 之一与 \(1\) 连通,将它们均并入 \(1\) 所在的连通块中。如果一个点 \(x\) 在时间 \(t-1\) 及之前已经与 \(1\) 连通,优先进行 \(x\) 的操作。

给出 \(n\) 个数,值域为 \(\{1,0,-1\}\)\(1\) 表示其一定与 \(1\) 连通,\(-1\) 表示一定不与 \(1\) 连通,\(0\) 表示无法确定是否连通,问是否存在合法的 \(\{t\}\)

\(n,m\le 2\times 10^5\)\(u_j\not=v_j\)\(1\le L_i\le R_i\le 10^9\)


C

一个 01 串,每次取出一个子串作为二进制数 \(x\),可以令 \(x\leftarrow x+2^k\)\(x-2^k\),其中 \(k\in \mathbb{N}\),但需满足 \(x\) 时刻 \(\ge 0\),问使 \(x\) 变为 \(0\) 的最小步数。串支持单点修。

\(n,q\le 3\times 10^5\)


有一个简单的结论。若两段 \(1\) 的间隔为 \(1\),可以将它们合并减少 \(1\) 步。此外的连续段代价为 \(2\),孤立点代价为 \(1\)。把这个放到线段树上维护,然后写的太屎就睡觉去了。

考虑 \(O(n)\) DP。记 \(f_{i,0/1}\) 表示使得第 \(i\) 位为 \(0\),当前不进位和进位的最小步数。

  • \(f_{i,0}=f_{i-1,0}+[s_i=1]\),若 \(s_i=0\),同时对 \(f_{i-1,1}+1\)\(\min\)

前者是说可以当 \(-2^k\) 使当前位为 \(0\),后者的意思是如果在 \(i-1\) 位做了进位操作,这一位必须为 \(0\)

  • \(f_{i,1}=f_{i-1,1}+[s_i=0]\),若 \(s_i=1\),同时对 \(f_{i-1,0}+1\)\(\min\)

初始值 \(f_{l-1,0}=0,f_{l-1,1}=\infty\),答案为 \(\min(f_{r,0},f_{r,1}+1)\)

和前面差不多。

于是乎考虑 \(i\) 处的转移矩阵。时间复杂度 \(O(q\log n)\)

点击查看代码
#include<bits/stdc++.h>
#define N 300010
#define inf 1e9
using namespace std;
int read(){
	int x=0,w=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*w;
}
struct Mat{
	int a[2][2];
	Mat(){a[0][0]=a[0][1]=a[1][0]=a[1][1]=inf;}
	Mat operator*(const Mat &b)const{
		Mat ret;
		for(int i=0;i<2;i++)
			for(int k=0;k<2;k++)
				for(int j=0;j<2;j++)
					ret.a[i][j]=min(ret.a[i][j],a[i][k]+b.a[k][j]);
		return ret;
	}
}tr[N<<2];
int n;char _s[N];int s[N];
#define ls p<<1
#define rs p<<1|1
void pushup(int p){
	tr[p]=tr[ls]*tr[rs];
}
void build(int p,int l,int r){
	if(l==r){
		tr[p].a[0][0]=s[l],tr[p].a[1][0]=!s[l]?1:inf;
		tr[p].a[0][1]=s[l]?1:inf,tr[p].a[1][1]=!s[l];
		return;
	}
	int mid=(l+r)>>1;
	build(ls,l,mid),build(rs,mid+1,r);
	pushup(p);
}
void modify(int p,int l,int r,int x){
	if(l==r){
		tr[p].a[0][0]=s[l],tr[p].a[1][0]=!s[l]?1:inf;
		tr[p].a[0][1]=s[l]?1:inf,tr[p].a[1][1]=!s[l];
		return;
	}
	int mid=(l+r)>>1;
	(x<=mid)?modify(ls,l,mid,x):modify(rs,mid+1,r,x);
	pushup(p);
}
Mat ans;
void query(int p,int l,int r,int L,int R){
	if(L<=l&&r<=R)return ans=ans*tr[p],void();
	int mid=(l+r)>>1;
	if(L<=mid)query(ls,l,mid,L,R);
	if(R>mid)query(rs,mid+1,r,L,R);
}
int main(){
	n=read(),scanf("%s",_s+1);
	for(int i=1;i<=n;i++)s[i]=_s[i]-'0';
	build(1,1,n);
	int m=read(),opt,l,r,x,y;
	while(m--){
		opt=read();
		if(opt==1){
			l=read(),r=read();
			ans.a[0][0]=0,ans.a[0][1]=inf;
			query(1,1,n,l,r);
			printf("%d\n",min(ans.a[0][0],ans.a[0][1]+1));
		}
		if(opt==2){
			x=read(),y=read();
			s[x]=y,modify(1,1,n,x);
		}
	}
	
	return 0;
}

D

树上随机游走。具体地,在点 \(u\)\(p_u\) 的概率停留,\(1-p_u\) 的概率向任意相邻节点移动。

求到达 \(1\) 节点的时间的 \(k\) 次方的期望值。答案模 \(998244353\)

\(n\cdot k\le 10^6\)\(1\le n\le 10^5\)\(0\le k\le 10^5\)\(0\le p_i<1\)


wzr 暴力求逆草过去了?