ARC 203

A

我不会柿子解法。

考虑二分,对于 \(x\) 的判定,一定是尽量平均的分到每一个人。然后,每一组的每一个全胜者在其他每一个组一定要匹配上一个非全胜者。求出这个组以外的非全胜者个数最小值就可以判定了。

B

\(A\rightarrow B\) 有点难做,因此套路的想要 \(A,B\) 都到达最小值然后判断是不是相等。对于 \(A\) 做这个算法即可,\(B\) 一样:

  • 现在 \(0\sim i-1\) 都是 \(0\),目标把 \(i\)\(1\) 变成 \(0\)

  • 找到一个 \(i+1\) 往后的 \(0\),如果没有 \(0\)吗,说明已经是 00...0011...11 的形式,结束。否则可以找到一个 \(0\)

  • 如果能找到 \(0\) 使得后面是 \(1\),直接交换,归纳到子问题。

  • 否则只能是前面有 \(1\) 的。如果前面的 \(1\) 不是 \(i\),可以先交换,交换后出现一个上面的情况。因此也是可以归纳下去的。

  • 如果前面的 \(1\) 只能是 \(i\),说明 \(A\) 中只有一个 \(1\)

那么对于 \(1\) 的个数 \(\ge 2\) 已经做完了。考虑只有一个的问题。

发现相同的边角是可以的,不同的边角是不行的,只有一个是边角是不行的,两个都不是边角是可以的。

C

重要:\(k\le h+w\)。记 \(r=(h(w-1)+w(h-1)-(h+w-2))\)

  • \(k<h+w-2\):答案是 \(0\)

  • \(k=h+w-2\):答案是 \(\binom{h+w-2}{h-1}\)

  • \(k=h+w-1\):答案是 \(\binom{h+w-2}{h-1}\times r\)。即选择一条路径和不是路径上的一点。

  • \(k=h+w\)。有两种路径长度。

    • 长度 \(h+w-2\)\(\binom{h+w-2}{h-1}\times \binom{r}{2}\) 只在有两条不同路径的时候会统计两遍。这个会在有 \(2\times 2\) 被连接出现,那么压缩成 \(1\times 1\),在转化为在这个路径上选择一个扩大。因此减去 \(\binom{h+w-4}{h-2}\times (h+w-3)\)

    • 长度为 \(h+w\)。一定有一个竖着的往上走,两边都是横着的,或者一个横着的往左走,两边都是竖着的。现在只考虑第一种,第二种类似。考虑这个横竖横,整体折下去,变成一个往下的竖,再在这个里面选择一个不是边缘的竖变回去,相当于统计了答案。那么就是 \(h+1\) 个竖,\(w-3\) 个横。\(\binom{h+w-1}{w-3}\times (h-1)\)

D

比起加入,删除更容易。加入有这几种情况:

  • \(00\rightarrow 000\)

  • \(01\rightarrow 011\)

  • \(10\rightarrow 110\)

  • \(11\rightarrow 101\)

那么可以得出,连续的 \(0\) 可以不超过 \(2\) 个,连续的 \(1\) 可以不超过 \(1\) 个(前提是边上有 \(0\)),并且 \(101\) 可以变成 \(11\)

发现得到的 \(B\) 一定是 \(C(100100\cdots 100)D\)\(C,D\) 比较短,中间重复。

重复的次数是好求出来的。发现是 \(a_i=0,a_{i-1}=1,a_{i+1}=0\)\(i\) 的个数。那么相应的可以求出对应的区间。

现在就是有两边,没有连续的 \(0\),求答案。分类讨论一下即可。

对于没有 \(100\) 的也要特殊判断。赛时代码:

#include <bits/stdc++.h>

using namespace std;

using ll = long long;

const int N = 2e5+5;

int n,q,a[N],cnt,is[N],ctok,bit[N];
set<int> st;

void M(int p,int v){
	while (p<N){
		bit[p]+=v,p+=p&-p;
	}
}

int Q(int p){
	int res=0;
	while (p){
		res+=bit[p],p-=p&-p;
	}
	return res;
}

void upd(int x){
	if (x<=1 || x>=n) return;
	if (a[x-1]==1 && a[x]==0 && a[x+1]==0){
		ctok++,is[x]=1;
		st.insert(x);
	}
	else{
		if (is[x]) st.erase(x);
		is[x]=0;
	}
}

void fst(int x){
	upd(x);
	M(x,a[x]);
}

void mod(int x){
	ctok-=is[x]+is[x-1]+is[x+1];
	cnt+=(a[x]==1?-1:1);
	if (a[x]==1) M(x,-1);
	else M(x,1);
	a[x]=a[x]^1;
	upd(x),upd(x-1),upd(x+1);
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);

	cin>>n;
	for (int i=1; i<=n; i++){
		cin>>a[i];
		cnt+=a[i];
	}
	for (int i=1; i<=n; i++){
		fst(i);
	}
	cin>>q;
	while (q--){
		int x;
		cin>>x;
		mod(x);
		if (cnt==0){
			cout<<2<<"\n";
			continue;
		}
		if (cnt==n){
			cout<<n<<"\n";
			continue;
		}
		int ans=ctok*3;
		assert(ctok==(int)st.size());
		if (ctok==0){
			int tc=(a[1]==0 && a[2]==0);
			if (a[1]==0 && a[n]==0 && cnt!=0){
				cout<<3+tc<<"\n";
			}
			else 
				cout<<2+tc<<"\n";
			continue;
		}
		int l=(*st.begin())-2;
		int r=(*st.rbegin())+2;
		// 1~l r~n
		int lb=0,rb=l+1;
		while (lb+1<rb){
			int mid=lb+rb>>1;
			if (Q(l)-Q(mid-1)==l-mid+1) rb=mid;
			else lb=mid;
		}
		if (1<=l) l=lb;
		lb=r-1,rb=n+1;
		while (lb+1<rb){
			int mid=lb+rb>>1;
			if (Q(mid)-Q(r-1)==0) lb=mid;
			else rb=mid; 
		}
		if (r<=n) r=rb;
		if (1<=l){
			if (a[1]==0){
				ans++;
				if (2<=l && a[2]==0) ans++;
			}
		}
		if (r<=n){
			if (a[n]==1) ans++;
			else ans+=min(2,n-r+1);
		}
		cout<<ans<<"\n";
	}
	return 0;
}
posted @ 2025-08-04 08:24  SFlyer  阅读(15)  评论(0)    收藏  举报