A - 一道可持久化并查集好题
出题人: zhberzhberzhber
通过/提交: 17/3717/3717/37
题解: 此题数据极小,直接模拟即可。撤销操作就是不执行前面 kkk 次操作,把撤销操作视为返回 kkk 次之前的历史版本。用state[i][j][k]
表示第 iii 次操作后第 jjj 个点和第 kkk 个点是否联通,对于 111 操作,复制上一次操作之后的状态,然后考虑新增的经过a−ba-ba−b 边而可到达的点对。这些新点对(记为x^y
)一定是 xxx 在一侧,yyy 在另一侧,由于新加了 a−ba-ba−b 而联通。那么分别找 a,ba,ba,b 能到达的点放到两集合内,取两个集合各一点配对都设为联通即可O(n2)O(n^2)O(n2) 。或者直接floyd
传递闭包O(n3)O(n^3)O(n3) 。对于第 222 种操作,复制上一次的状态,暴力找和它联通的点数。对于第三种操作,复制的不是上一次的状态,而是第 x−k−1x-k-1x−k−1 次的状态。时间复杂度 O(n2m)O(n^2m)O(n2m) ,空间复杂度O(n2m)O(n^2m)O(n2m) 。
#include<bits/stdc++.h>
#define maxn 100 + 10
using namespace std;
int state[maxn][maxn][maxn];
int n,m;
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) state[0][i][i]=1;
for (int i=1;i<=m;i++)
{
int op;scanf("%d",&op);
if (op==1)
{
for (int j=1;j<=n;j++)
for (int k=1;k<=n;k++)
state[i][j][k]=state[i-1][j][k];
int a,b;scanf("%d%d",&a,&b);
vector<int>A,B;A.clear();B.clear();
for (int j=1;j<=n;j++)
{
if (state[i][a][j])A.push_back(j);
if (state[i][b][j])B.push_back(j);
}
for (int j=0;j<A.size();j++)
for (int k=0;k<B.size();k++)
{
state[i][A[j]][B[k]]=1;
state[i][B[k]][A[j]]=1;
}
}else if (op==2)
{
for (int j=1;j<=n;j++)
for (int k=1;k<=n;k++)
state[i][j][k]=state[i-1][j][k];
int a,sum=0;scanf("%d",&a);
for (int j=1;j<=n;j++)if (state[i][j][a])sum++;
printf("%d\n",sum);
}else if (op==3)
{
int k;scanf("%d",&k);
for (int j=1;j<=n;j++)
for (int l=1;l<=n;l++)
state[i][j][l]=state[i-k-1][j][l];
}
}
}
B - zhb love math
出题人: strawberrystrawberrystrawberry
通过/提交: 1/21/21/2
题解: 考虑每个元素 bib_ibi 对答案的贡献,一定是一些包含 bib_ibi 的区间,且区间除了它以外,没有 bjb_jbj 是 bib_ibi 的因数。容易想到的是,对每个 bib_ibi 找到包含它可行区间的最左边 lil_ili 和包含它可行区间的最右边 rir_iri 那么任何区间 [l,r] l,r∈[li,ri][l,r]\ l,r∈[l_i,r_i][l,r] l,r∈[li,ri] 都是答案,这样的区间有 (i−li+1)×(ri−i+1)(i-l_i+1)×(r_i-i+1)(i−li+1)×(ri−i+1) 个,朴素的 O(n2)O(n^2)O(n2) 想法是从 iii 开始往左往右扫,找到第一个 bj%bi=0b_j\%b_i=0bj%bi=0 的 jjj 就是边界,因为 n≤105n\leq 10^5n≤105,是不能通过这题的。考虑怎么优化,当枚举到 iii 的时候, 对于 iii 左侧的 bjb_jbj 如果 bj%bi=0b_j\%b_i=0bj%bi=0 那么对于位置 jjj 的 rjr_jrj 最右只能到 (i−1)(i-1)(i−1) 的位置!, 因为 bi≤104b_i\leq 10^4bi≤104 ,所以可以直接枚举 bib_ibi 的倍数 jjj 去更新答案,从左往右扫以 pre[i]
表示