【学习笔记】ARC题目选做01

ARC147

Min Diff Sum

我是sb我是sb

数学题好难

L = max ⁡ ( L i ) L=\max(L_i) L=max(Li) R = min ⁡ ( R i ) R=\min(R_i) R=min(Ri)(经典结论)

1.1 1.1 1.1 L ≤ R L\le R LR,那么存在 X X X使得对于任意 i i i满足 L i ≤ X ≤ R i L_i\le X\le R_i LiXRi,显然答案是 0 0 0 这个界我是真没想到
1.2 1.2 1.2 L > R L>R L>R,显然最优方案中任意 i i i满足 R ≤ X i ≤ L R\le X_i\le L RXiL,然后递归考虑,设 C C C表示剩下 n − 2 n-2 n2个区间两两的代价,答案是 C + ( L − R ) + ∑ i ≠ l , r ∣ X i − R ∣ + ∣ L − X i ∣ C+(L-R)+\sum_{i\ne l,r}|X_i-R|+|L-X_i| C+(LR)+i=l,rXiR+LXi 。显然我们只要最小化 C C C即可。我们递归直到 1.1 1.1 1.1的情况,然后所有区间都设成 X X X,再递归回来即可。

复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)。第一步转化并不容易。为啥大家都会啊

Sets Scores

思维题。考虑固定相邻两个集合删去或添加的那个数,显然我们只需要枚举 S 1 S_1 S1,注意到所有 S 1 S_1 S1产生的贡献求和等于 n m n^m nm,答案是 m n − 1 × n m m^{n-1}\times n^m mn1×nm

Examination

基本想法是贪心。

ARC141

Increasing Prefix XOR

序列对 ( A , B ) (A,B) (A,B)合法的条件为:

1.1 1.1 1.1 A A A序列最高位上的 1 1 1单调递增
1.2 1.2 1.2 A n ≤ m A_n\le m Anm

基于上述观察,可以写数位 d p dp dp。复杂度 O ( log ⁡ 2 n ) O(\log^2n) O(log2n)

Bracket and Permutation

思维题。

括号序列合法的条件是任意前缀中左括号数量大于等于右括号数量。

如果 P 2 i − 1 > P 2 i P_{2i-1}>P_{2i} P2i1>P2i,那么 S P 2 i − 1 = ( S_{P_{2i-1}}=( SP2i1=( 并且 S P 2 i = ) S_{P_{2i}}=) SP2i=)

如果 Q 2 i − 1 < Q 2 i Q_{2i-1}<Q_{2i} Q2i1<Q2i,那么 S Q 2 i − 1 = ( S_{Q_{2i-1}}=( SQ2i1=( 并且 S Q 2 i = ) S_{Q_{2i}}=) SQ2i=)

我们断言此时的字符串 S S S是可还原的。

考虑出现无法匹配的右括号时会把最近的左括号交换到前面,那么任意前缀 < 0 <0 <0的位置会被移走,考虑 2 i 2i 2i 2 i − 1 2i-1 2i1两个位置,都会在从前往后或从后往前的过程中被交换,也就是说每个位置至少被交换一次。

直接检验 S S S即可。复杂度 O ( n ) O(n) O(n)

Non-divisible Set

如果把 2 2 2的次幂分离出来,会产生 1 , 3 , . . , 2 n − 1 1,3,..,2n-1 1,3,..,2n1 n n n个集合,并且恰好每个集合最多包含一个数。

显然最终要选 n n n个数,所以每个集合都必须选恰好一个数。

那么只需求出每个集合的最小和最大取值,对于一个数能否被取到,只需判断是否在区间内即可。

复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

Sliding Edge on Torus

首先可以按 j − i j-i ji将这些点分成 n n n组,那么一次操作相当于对其中的两组进行交错连边。

如果两个组之间存在两个点是联通的,那么我们称这两个组是联通的。

对于一个大连通块,我们发现一些性质:

1.1 1.1 1.1 假设大连通块内部有 U U U个小连通块,那么从任意一个组的前 U U U个点出发,恰好能遍历完所有点。换句话说,从任意一组的 i i i出发能走到这一组中 i + k U i+kU i+kU的点

考虑归纳证明。

如果两个组之前是不连通的,那么从第 u u u组的 i i i出发,走到右边第 v v v组再走回来,注意到中间经过的那条边抵消了,此时的编号应该是 i + k 1 U + k 2 V i+k1U+k2V i+k1U+k2V,因此 i i i能走到的 j j j应该满足 j ≡ i ( m o d gcd ⁡ ( U , V ) ) j\equiv i\pmod {\gcd(U,V)} ji(modgcd(U,V)),这说明新的连通块数目至少为 gcd ⁡ ( U , V ) \gcd(U,V) gcd(U,V),同时连通块内的任意一点都能走到第 u u u组的 i ′ i' i节点,那么 i ′ i' i又能走到第 u u u组的前 gcd ⁡ ( U , V ) \gcd(U,V) gcd(U,V)个点,因此从第 u u u组的前 gcd ⁡ ( U , V ) \gcd(U,V) gcd(U,V)个点出发能够遍历完连通块内所有点,这说明新的大连通块内连通块数目恰好为 gcd ⁡ ( U , V ) \gcd(U,V) gcd(U,V)

其次,因为连边具有对称性,因此如果从第 u u u组的 i i i出发能够到达第 v v v组的 j j j,那么从第 u u u组的 i + 1 i+1 i+1出发一定能到达第 v v v组的 j + 1 j+1 j+1,这说明从第 u u u组的前 gcd ⁡ ( U , V ) \gcd(U,V) gcd(U,V)个点出发到达第 v v v组的点恰好是一段区间,并且第 v v v组的 j j j j + gcd ⁡ ( U , V ) j+\gcd(U,V) j+gcd(U,V)在同一个连通块内,因此归纳假设成立。

如果两个组之前是联通的,设此时第 u u u组到第 v v v组的偏移量为 δ \delta δ,那么可以先走新增的边权为 W W W的边到第 v v v组,然后再花费 − δ -\delta δ走回第 u u u组,显然此时新的连通块数目为 gcd ⁡ ( U , W − δ ) \gcd(U,W-\delta) gcd(U,Wδ)

显然可以用带权并查集维护。复杂度 O ( n ) O(n) O(n)

#include<bits/stdc++.h>
#define fi first
#define se second
#define ll long long
#define pb push_back
#define inf 0x3f3f3f3f
using namespace std;
int n,m,cnt,fa[200005],f[200005],fx[200005];
ll res;
int find(int x){
	if(fa[x]==x)return x;
	int y=fa[x];fa[x]=find(fa[x]),fx[x]=(fx[x]+fx[y])%f[fa[x]];
    return fa[x];
}
int gcd(int x,int y){return y==0?x:gcd(y,x%y);}
int main(){
	cin>>n>>m,res=(ll)n*n;
	for(int i=1;i<=n;i++)fa[i]=i,f[i]=n;
	for(int i=1;i<=m;i++){
		int a,b,c,d;cin>>a>>b>>c>>d;
		int x=(b-a+n)%n+1,y=(d-c+n)%n+1,z=(c-a+n)%n;
		int u=find(x),v=find(y);
		if(u!=v){
			res-=f[u]+f[v]-gcd(f[u],f[v]),fa[u]=v,f[v]=gcd(f[u],f[v]),fx[u]=(-fx[x]+z+fx[y]+n)%f[v];
		}
		else {
			res-=f[u]-gcd(f[u],(z-fx[x]+fx[y]+n)%n),f[u]=gcd(f[u],(z-fx[x]+fx[y]+n)%n);
		}cout<<res<<"\n";
	}
}

ARC145

AB Palindrome

对首尾字母分类讨论即可。注意 n = 2 n=2 n=2的情况。

Split and Maximize

首先猜结论。要让分数最大一定是 2 i − 1 2i-1 2i1 2 i 2i 2i配对。

然后把 2 i − 1 2i-1 2i1 2 i 2i 2i都看作种类 i i i。发现每次就是往 A A A集合或者 B B B集合中塞一个数,我们钦定 A A A集合个数不超过 B B B集合个数,那么就是卡特兰数。

答案是 C ( n ) × 2 n × n ! C(n)\times 2^n\times n! C(n)×2n×n!

Non Arithmetic Progression Set

构造题。

首先把限制写成 2 y = x + z 2y=x+z 2y=x+z便于观察。

考虑在 3 3 3进制意义下,如果 x x x, y y y, z z z 3 3 3进制表示中每一位都是 0 0 0 1 1 1,那么就不会存在进位,显然是合法的。

同时我们注意到,如果我们对集合 S S S中的每个数减去 Δ Δ Δ,那么 S S S仍然是合法的。

那么我们只需要构造 ∑ s ∈ S s ≡ M ( m o d n ) \sum_{s\in S}s\equiv M\pmod n sSsM(modn)即可。

下一步神仙操作:我们任意找 n n n个最低位是 0 0 0的合法的数,然后通过调整最低位来改变 ∑ s ∈ S s   m o d   n \sum_{s\in S}s\bmod n sSsmodn !!

Adjacent XOR

哲学抽象线性代数

反过来考虑,只需让 B i ′ B'_i Bi同时变成 ⨁ j = 1 i B i \bigoplus_{j=1}^iB_i j=1iBi即可。

注意到 B i ′ B'_i Bi可以表示成 B i ⨁ { B 1 , . . , B i − 1 } B_i\bigoplus \{B_1,..,B_{i-1}\} Bi{B1,..,Bi1}的一个子集。归纳法自证不难。

考虑从后往前构造。此处 B i ⨁ A i B_i\bigoplus A_i BiAi应在 { B 1 , . . . , B i − 1 } \{B_1,...,B_{i-1}\} {B1,...,Bi1}张成的子空间中。记 X = ( ⨁ j = 1 i B j ′ ) ⨁ A i X=(\bigoplus_{j=1}^iB'_j)\bigoplus A_i X=(j=1iBj)Ai,不妨考虑一组 { B 1 , . . . , B i − 1 } \{B_1,...,B_{i-1}\} {B1,...,Bi1}的基,那么每一个 B i ′ B'_i Bi都可以由它及以前的基表示出来,并且不包含在它以后的基。视 X X X基的表现形式为 B i 1 ⨁ B i 2 ⨁ . . . B i k B_{i1}\bigoplus B_{i2}\bigoplus ...B_{ik} Bi1Bi2...Bik。注意到操作 i k + 1 ik+1 ik+1 B i k B_{ik} Bik的出现次数奇偶性恰好改变一次( B i k B_{ik} Bik本身是基),并且这里只会改变 X X X B 1 ∼ i k B_{1\sim ik} B1ik的系数,那么对于 n n n个位置每个都至多操作 m m m次,总操作数 O ( n m ) = 60000 O(nm)=60000 O(nm)=60000

难点在于如何找到 X X X对于基 { B i ′ 1 , B i ′ 2 , . . . , B i ′ r } \{B_{i'1},B_{i'2},...,B_{i'r}\} {Bi1,Bi2,...,Bir}的每一项的系数。可以考虑构造一组等价的基,其中每个新基是关于 { B i ′ 1 , B i ′ 2 , . . . , B i ′ r } \{B_{i'1},B_{i'2},...,B_{i'r}\} {Bi1,Bi2,...,Bir}的"多项式"。

时间复杂度 O ( n 2 m ) O(n^2m) O(n2m)

#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define int ll
using namespace std;
int n,a[1005],b[1005],b2[1005];
int bit[65],f[65][65],f2[65],stk[65],cnt;
vector<int>v;
bool ins(int x,int y){
	memset(f2,0,sizeof f2);
	for(int i=59;i>=0;i--){
		if(x>>i&1){
			if(!bit[i]){
				bit[i]=x,f2[++cnt]=1,stk[cnt]=y;
				for(int j=1;j<=cnt;j++)f[i][j]=f2[j];
				return 1;
			}x^=bit[i];for(int j=1;j<=cnt;j++)f2[j]^=f[i][j];
		}
	}return 0;
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n;for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<=n;i++)cin>>b[i],b2[i]=b[i];
	for(int i=1;i<=n;i++){
		if(ins(a[i]^b[i],i)){
			cout<<"No";
			return 0;
		}ins(b[i],i);
	}
	for(int i=n;i>=1;i--){
		int X=a[i];for(int j=1;j<=i;j++)X^=b2[j];
		memset(bit,0,sizeof bit),cnt=0;
		for(int j=1;j<i;j++)ins(b[j],j);
		while(X){
			memset(f2,0,sizeof f2);
			int X2=X;
			for(int j=59;j>=0;j--){
				if(X2>>j&1){
					for(int k=1;k<=cnt;k++)f2[k]^=f[j][k];
					X2^=bit[j];
				}
			}
			for(int j=cnt;j>=1;j--){
				if(f2[j]){
					v.pb(stk[j]+1);
					for(int k=1;k<=stk[j]+1;k++){
						X^=b2[k-1],b2[k]^=b2[k-1];
					}
					break;
				}
			}
		}v.pb(i);
		for(int j=1;j<=i;j++)b2[j]^=b2[j-1];
	}cout<<"Yes"<<"\n"<<v.size()<<"\n";
	reverse(v.begin(),v.end());
	for(auto x:v)cout<<x<<' ';
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值