Gym102832K. Ragdoll(CCPC长春)
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gym102832K. Ragdoll(CCPC长春)相关的知识,希望对你有一定的参考价值。
题意:
n个点,每个点都有自己的权值
a
i
a_i
ai,一开始第i个点在第i个集合里。
如果一对点(i,j)是bad当且仅当满足i和j在同一个集合里,且
g
c
d
(
a
i
,
a
j
)
=
a
i
⊕
a
j
gcd(a_i,a_j)=a_i⊕a_j
gcd(ai,aj)=ai⊕aj
现在有3种操作:
- 新增一个点x(在新的一个集合里),值为v
- 合并两个集合x和y
- 将点x的值改为v
有m个操作,请输出每次操作后有多少对点是bad
题解:
一开始无从下手,因为这个式子不知道该如何应用
这里有个很巧妙的转换,
a
i
⊕
a
j
⩾
∣
a
i
−
a
j
∣
⩾
g
c
d
(
a
i
,
a
j
)
a_i⊕a_j ⩾|a_i-a_j|⩾gcd(a_i,a_j)
ai⊕aj⩾∣ai−aj∣⩾gcd(ai,aj),如果我们要让等式成立,则需要满足:
- a i ⊕ a j = ∣ a i − a j ∣ a_i⊕a_j=|a_i-a_j| ai⊕aj=∣ai−aj∣
- ∣ a i − a j ∣ = g c d ( a i , a j ) |a_i-a_j|=gcd(a_i,a_j) ∣ai−aj∣=gcd(ai,aj)
转换证明:
a
⊕
b
>
=
a
−
b
a⊕b>=a-b
a⊕b>=a−b,这个式子是显然成立的,用二进制思想去考虑
g
c
d
(
a
,
b
)
<
=
a
−
b
gcd(a,b)<=a-b
gcd(a,b)<=a−b:由于gcd(a,b)是b的因子,gcd(a,b)是a的因子,所以gcd(a,b)就是(a-b)的因子,所以gcd(a,b)一定小于等于a-b
∣
a
i
−
a
j
∣
=
g
c
d
(
a
i
,
a
j
)
|a_i-a_j|=gcd(a_i,a_j)
∣ai−aj∣=gcd(ai,aj)
a
j
=
a
i
+
g
c
d
(
a
i
,
a
j
)
a_j=a_i+gcd(a_i,a_j)
aj=ai+gcd(ai,aj)或者
a
j
=
a
i
−
g
c
d
(
a
i
,
a
j
)
a_j=a_i-gcd(a_i,a_j)
aj=ai−gcd(ai,aj)
而
g
c
d
(
a
i
,
a
j
)
gcd(a_i,a_j)
gcd(ai,aj)是
a
i
a_i
ai的因子
因此我们可以枚举
a
i
a_i
ai,然后枚举
a
i
a_i
ai的因子,这样就求出对于
a
i
a_i
ai而言合法的
a
j
a_j
aj,用vector存下来。相当于我们可以预处理出所有是bad的点对
我们再看三个操作,这种集合操作,都可以用并查集来维护
对于操作1,就是新加一个集合
对于操作2,合并两个集合,如果我们直接盲目合并,复杂度是O(n),这里用到启发式合并,把小的集合合并到大的集合中,这样复杂度降低为O(log)
对于操作3,我们先去掉原先元素可能组成的bad点对,改成数v后再加入新的bad点对
在每次操作中,维护着答案,如何维护呢?因为我们预处理出所有点对,合并时两个集合时,就枚举小集合所有元素,看大集合内有多少可以构成bad点对,更新答案ans。修改数时就是删除原先,加上新填
unordered_map速度更快
详细内容看代码
代码:
#include <bits/stdc++.h>
#include <unordered_map>
#define debug(a, b) printf("%s = %d\\n", a, b);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll= 1e18;
const int INF_int= 0x3f3f3f3f;
void read(){};
template <typename _Tp, typename... _Tps> void read(_Tp& x, _Tps&... Ar)
{
x= 0;
char c= getchar();
bool flag= 0;
while (c < '0' || c > '9')
flag|= (c == '-'), c= getchar();
while (c >= '0' && c <= '9')
x= (x << 3) + (x << 1) + (c ^ 48), c= getchar();
if (flag)
x= -x;
read(Ar...);
}
template <typename T> inline void write(T x)
{
if (x < 0) {
x= ~(x - 1);
putchar('-');
}
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
void rd_test()
{
#ifdef ONLINE_JUDGE
#else
startTime = clock ();
freopen("data.in", "r", stdin);
#endif
}
void Time_test()
{
#ifdef ONLINE_JUDGE
#else
endTime= clock();
printf("\\nRun Time:%lfs\\n", (double)(endTime - startTime) / CLOCKS_PER_SEC);
#endif
}
const int maxn=5e5+9;
int n,m;
int a[maxn];
vector<int>g[maxn];
int fa[maxn];
int sz[maxn];
ll ans=0;
unordered_map<int,ll>mp[maxn];
int gcd(int a,int b){
if(b)return gcd(b,a%b);
return a;
}
int find(int x){
if(fa[x]==x)return x;
return fa[x]=find(fa[x]);
}
void work(int x){
for(int i=1;i*i<=x;i++){//枚举因子
if(x%i==0){
int tmp=x-i;
if((tmp^x)==gcd(tmp,x)&&tmp!=0)//符合bad的点对
g[x].push_back(tmp);
tmp=x+i;
if((tmp^x)==gcd(tmp,x)&&tmp<=200000)
g[x].push_back(tmp);
if(i!=x/i){
tmp=x-x/i;
if((tmp^x)==gcd(tmp,x)&&tmp!=0)
g[x].push_back(tmp);
tmp=x+x/i;
if((tmp^x)==gcd(tmp,x)&&tmp!=200000)
g[x].push_back(tmp);
}
}
}
}
void merge以上是关于Gym102832K. Ragdoll(CCPC长春)的主要内容,如果未能解决你的问题,请参考以下文章
Meaningless Sequence Gym - 102832D
2020 CCPC 长春 K. Ragdoll(预处理+启发式合并)
2020第6届中国大学生程序设计竞赛CCPC长春站, 签到题3题