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
L≤R,那么存在
X
X
X使得对于任意
i
i
i满足
L
i
≤
X
≤
R
i
L_i\le X\le R_i
Li≤X≤Ri,显然答案是
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
R≤Xi≤L,然后递归考虑,设
C
C
C表示剩下
n
−
2
n-2
n−2个区间两两的代价,答案是
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+(L−R)+∑i=l,r∣Xi−R∣+∣L−Xi∣ 。显然我们只要最小化
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 mn−1×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
An≤m
基于上述观察,可以写数位 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} P2i−1>P2i,那么 S P 2 i − 1 = ( S_{P_{2i-1}}=( SP2i−1=( 并且 S P 2 i = ) S_{P_{2i}}=) SP2i=)
如果 Q 2 i − 1 < Q 2 i Q_{2i-1}<Q_{2i} Q2i−1<Q2i,那么 S Q 2 i − 1 = ( S_{Q_{2i-1}}=( SQ2i−1=( 并且 S Q 2 i = ) S_{Q_{2i}}=) SQ2i=)
我们断言此时的字符串 S S S是可还原的。
考虑出现无法匹配的右括号时会把最近的左括号交换到前面,那么任意前缀 < 0 <0 <0的位置会被移走,考虑 2 i 2i 2i和 2 i − 1 2i-1 2i−1两个位置,都会在从前往后或从后往前的过程中被交换,也就是说每个位置至少被交换一次。
直接检验 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,..,2n−1共 n n n个集合,并且恰好每个集合最多包含一个数。
显然最终要选 n n n个数,所以每个集合都必须选恰好一个数。
那么只需求出每个集合的最小和最大取值,对于一个数能否被取到,只需判断是否在区间内即可。
复杂度 O ( n log n ) O(n\log n) O(nlogn) 。
Sliding Edge on Torus
首先可以按 j − i j-i j−i将这些点分成 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)} j≡i(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 2i−1和 2 i 2i 2i配对。
然后把 2 i − 1 2i-1 2i−1和 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 ∑s∈Ss≡M(modn)即可。
下一步神仙操作:我们任意找 n n n个最低位是 0 0 0的合法的数,然后通过调整最低位来改变 ∑ s ∈ S s m o d n \sum_{s\in S}s\bmod n ∑s∈Ssmodn !!
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,..,Bi−1}的一个子集。归纳法自证不难。
考虑从后往前构造。此处 B i ⨁ A i B_i\bigoplus A_i Bi⨁Ai应在 { B 1 , . . . , B i − 1 } \{B_1,...,B_{i-1}\} {B1,...,Bi−1}张成的子空间中。记 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,...,Bi−1}的基,那么每一个 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} Bi1⨁Bi2⨁...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} B1∼ik的系数,那么对于 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}\} {Bi′1,Bi′2,...,Bi′r}的每一项的系数。可以考虑构造一组等价的基,其中每个新基是关于 { B i ′ 1 , B i ′ 2 , . . . , B i ′ r } \{B_{i'1},B_{i'2},...,B_{i'r}\} {Bi′1,Bi′2,...,Bi′r}的"多项式"。
时间复杂度 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<<' ';
}