Gym102832K. Ragdoll(CCPC长春)

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gym102832K. Ragdoll(CCPC长春)相关的知识,希望对你有一定的参考价值。

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)=aiaj
现在有3种操作:

  1. 新增一个点x(在新的一个集合里),值为v
  2. 合并两个集合x和y
  3. 将点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) aiajaiajgcd(ai,aj),如果我们要让等式成立,则需要满足:

  1. a i ​ ⊕ a j = ∣ a i − a j ∣ a_i​⊕a_j=|a_i-a_j| aiaj=aiaj
  2. ∣ a i − a j ∣ = g c d ( a i , a j ) |a_i-a_j|=gcd(a_i,a_j) aiaj=gcd(ai,aj)

转换证明:
a ⊕ b > = a − b a⊕b>=a-b ab>=ab,这个式子是显然成立的,用二进制思想去考虑
g c d ( a , b ) < = a − b gcd(a,b)<=a-b gcd(a,b)<=ab:由于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) aiaj=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=aigcd(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长春)的主要内容,如果未能解决你的问题,请参考以下文章

Strange Memory Gym - 102832F

Meaningless Sequence Gym - 102832D

2020 CCPC 长春 K. Ragdoll(预处理+启发式合并)

2020第6届中国大学生程序设计竞赛CCPC长春站, 签到题3题

2020第6届中国大学生程序设计竞赛CCPC长春站, 签到题3题

CCPC秦皇岛gym102361A. Angle Beats