[BZOJ4602][Sdoi2016]齒輪(加權並查集)
=== ===
這裡放傳送門
=== ===
題解
作為SDOI R2的題這題已經很良心了。。。然而ATP當時仍然寫掛了。。不是很懂自己為什麼這麼辣雞(╯‵□′)╯︵┻━┻
首先可以看出這個齒輪的轉動關係是具有傳遞性的,如果知道x和y的關係,也知道y和z的關係,就可以推出x和z的關係。具有這種關係的東西一般都可以用加權並查集來搞。對於每個元素給它維護一個dis[x],表示的含義是如果x的代表元素轉動1圈,x要轉動幾圈。每次讀入一個限制如果x和y不在同一個集合裡就進行合併。合併的時候先找到x的代表元素r1和y的代表元素r2,然後我們要把r2合併到r1上。要進行合併就要知道r1轉一圈的時候r2轉幾圈。設從讀入的資訊可以知道x轉一圈的時候y轉w圈,那麼如果r1轉了一圈,y就轉了
如果讀入的x和y在一個集合裡,那麼就可以用維護的資訊算出x轉了一圈的時候y轉了幾圈,和讀入的資訊進行比對就可以判定是否發生矛盾。
這個資料範圍看起來好像很小的樣子。。但是如果它出上n-1個資訊,每次都是當齒輪i轉動1圈的時候齒輪i+1轉動100圈,那麼最後就會發現當齒輪1轉動一圈的時候齒輪n會轉動
程式碼
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100
#define size 25
using namespace std;
int T,n,m,father[1010],num[110],prm[30];
bool flag;
struct info{
int p[30],type;
info(int X=0){
memset(p,0,sizeof(p));
type=1;
if (X==0) return;
if (X<0){type=0;X=-X;}
else type=1;
for (int i=1;i<=prm[0];i++){
if (X==1) break;
while (X%prm[i]==0){
++p[i];X/=prm[i];
}
}
}
info operator * (const info &a){
info c;
c.type=type^a.type^1;
for (int i=1;i<=size;i++)
c.p[i]=p[i]+a.p[i];
return c;
}
info operator / (const info &a){
info c;
c.type=type^a.type^1;
for (int i=1;i<=size;i++)
c.p[i]=p[i]-a.p[i];
return c;
}
bool operator == (const info &a)const{
if (type!=a.type) return false;
for (int i=1;i<=size;i++)
if (p[i]!=a.p[i]) return false;
return true;
}
bool operator != (const info &a)const{return !(*this==a);}
}dis[1010];
int find(int x){
if (x==father[x]) return x;
int tmp=find(father[x]);
dis[x]=dis[x]*dis[father[x]];
father[x]=tmp;
return father[x];
}
void get_prime(){
bool ext[110];
memset(ext,false,sizeof(ext));
for (int i=2;i<=100;i++){
if (ext[i]==false) prm[++prm[0]]=i;
for (int j=1;j<=prm[0];j++){
if (i*prm[j]>N) break;
ext[i*prm[j]]=true;
if (i%prm[j]==0) break;
}
}
for (int i=1;i<=prm[0];i++) num[prm[i]]=i;
}
int main()
{
scanf("%d",&T);
get_prime();
for (int wer=1;wer<=T;wer++){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++){
father[i]=i;dis[i]=info();
}
flag=false;
for (int i=1;i<=m;i++){
int u,v,x,y,r1,r2;
info tmp,X,Y;
scanf("%d%d%d%d",&u,&v,&x,&y);
if (flag==true) continue;
r1=find(u);r2=find(v);
X=info(x);Y=info(y);
tmp=dis[u]/dis[v];
Y=X/Y;
if (r1!=r2){
father[r1]=r2;
tmp=Y/tmp;
dis[r1]=tmp;
}else
if (tmp!=Y) flag=true;
}
printf("Case #%d: ",wer);
if (flag==false) printf("Yes\n");
else printf("No\n");
}
return 0;
}
偏偏在最後出現的補充說明
做題的時候一定要多考慮一下它的極端情況
相關推薦
[BZOJ4602][Sdoi2016]齒輪(加權並查集)
=== === 這裡放傳送門 === === 題解 作為SDOI R2的題這題已經很良心了。。。然而ATP當時仍然寫掛了。。不是很懂自己為什麼這麼辣雞(╯‵□′)╯︵┻━┻ 首先可以看出這個齒輪的轉動關係是具有傳遞性的,如果知道x和y的關係,也知道
bzoj4602 [Sdoi2016]齒輪 邊權並查集
把並查集的樹形結構畫出來,嘗試路徑壓縮,就是直接把邊權乘起來,表示當前節點轉1圈,父節點轉幾圈。。如果卡精度可以用取log或分解質因數。碼:#include<iostream> #inclu
【TOJ 3955】NKU ACM足球賽(加權並查集)
namespace 如果 main 加權並查集 幫助 iostream sof 報名人數 -- 描述 NKU ACM最近要舉行足球賽,作為此次賽事的負責人,Lee要對報名人員進行分隊。分隊要遵循如下原則: 一個人不能加入多支隊伍;不認識的人不能分在同一隊;如果a和b認識,
Cube Stacking P0J 1988(加權並查集)
ati initial mil ide art else display ans size Description Farmer John and Betsy are playing a game with N (1 <= N <= 30,000)id
POJ 1733 Parity game(加權並查集)
題意:這是一個01的串,然後有m個類似於詢問的東西,每次詢問都告訴你這個區間的和為奇數還是偶數,讓你判斷正確的有幾句,如果不正確,直接跳出 思路:和華中科技大學的決賽差不多,我們將奇數設為1,偶數為0,那我們可以發現他們的奇偶性可以用異或代替,然後就穿一樣了,加上判斷條件就OK了,記得離散化 程式碼:
A Bug's Life(加權並查集)
滴答滴答---題目連結 A Bug's Life(加權並查集) Description Background Professor Hopper is researching the sexual behavior of a rare species of bugs
A Bug's Life(加權並查集)
Description Background Professor Hopper is researching the sexual behavior of a rare species of bugs. He assumes that they feature t
hdu 2545 樹上戰爭(加權並查集)
題意:給出一顆樹,每次詢問樹上兩個節點到根的距離誰更近。。 #include <iostream> #include <cstdio> #include <cstring
重量差異 (加權並查集)
重量差異 10.11 思路: 加權並查集的經典應用。每個點儲存它與根節點的重量差,合併與路徑壓縮時維護一下就好。 離線的按秩合併可能會T掉。。。 #include <cstdio>
hdu 3234 異或(加權並查集)
有n(n<=20000)個未知的整數X0,X1,X2Xn-1,有以下Q個(Q<=40000)操作: I p v :告訴你Xp=v I p q v :告訴你Xp Xor Xq=v Q k p1 p2 … pk : 詢問 Xp1 Xor Xp2 .
POJ-1988 Cube Stacking (加權並查集)
題目大意: 給你編號從1到30000的大小相同的立方體,現在我有2種操作: 1.move 1,3表示把1放在3的上面。 還有一種情況是:假如1的下面還有一個2,3的下面還有一個4,那麼move1,3的意思就是把1所在的全部立方體放在3全部立方體的上面,而且保持原來1和3所
poj 1733 Parity game(種類並查集)
scanf split class ber ont dsm 種類 uil this 題意: 有0或1構成的一段區間總長度為n。m個詢問,每次詢問一段區間1的個數為奇數還是偶數,問從第一個詢問開始,前幾個詢問正確的個數有幾個; 思路:
GYM 101173 F.Free Figurines(貪心||並查集)
efi can 初始 typedef 多余 一個 class type pri 原題鏈接 題意:俄羅斯套娃,給出一個初始狀態和終止狀態,問至少需要多少步操作才能實現狀態轉化 貪心做法如果完全拆掉再重裝,答案是p[i]和q[i]中不為0的值的個數。現在要求尋找最小步數,顯
BZOJ 1370: [Baltic2003]Gang團夥(luogu 1892)(種類並查集)
col std max %d zoj pri get -s 題解 題面: bzoj題面有誤,還是看luogu的吧 https://www.luogu.org/problemnew/show/P1892 題解: 種類並查集。。 因為有敵人的敵人是朋友
POJ 2524 獨一無二的宗教(裸並查集)
路徑壓縮 tro not lines () using number rest targe 題目鏈接: http://poj.org/problem?id=2524 Ubiquitous Religions Time Limit: 5000MS Memory L
HDU 1213(裸並查集)(無變形)
line table #define The mar .cn tput KS ast 題目鏈接: http://acm.hdu.edu.cn/showproblem.php?pid=1213 How Many Tables Time Limit: 2000/1000 MS
Supermarket POJ - 1456 (貪心+並查集)
先將n個物品按價值降序排個序,從頭掃到尾,對於每一個物品i,判斷能不能在<=di的最大時間點賣掉。 #include<stdio.h> #include<algorithm> #include<iostream> #include<string
程式自動分析 (hash + 並查集)
在實現程式自動分析的過程中,常常需要判定一些約束條件是否能被同時滿足。 考慮一個約束滿足問題的簡化版本:假設$$x_1$$,$x_2$,$x_3$,…代表程式中出現的變數,給定n個形如$x_i=x_j$或$x_i≠x_j$的變數相等/不等的約束條件,請判定是否可以分別為每一個變數賦予恰當的值,使得上述所有約
【ZCMU1437】A Bug's Life(種類並查集)
題目連結 1437: A Bug's Life Time Limit: 1 Sec Memory Limit: 128 MB Submit: 113 Solved: 50 [Submit][Status][Web Board] Descript
洛谷P3295 [SCOI2016]萌萌噠(倍增+並查集)
傳送門 思路太妙了啊…… 容易才怪想到暴力,把區間內的每一個數字用並查集維護相等,然後設最後總共有$k$個並查集,那麼答案就是$9*10^{k-1}$(因為第一位不能為0) 考慮倍增。我們設$f[i][j]$表示區間$[i,i+2^j-1]$,那麼我們可以把原區間給拆成$log$個區間,