1. 程式人生 > >[BZOJ4602][Sdoi2016]齒輪(加權並查集)

[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就轉了d

is[x]w圈;而當y轉了dis[x]w圈的時候,r2轉了dis[x]wdis[y]圈。關係如下圖:
這裡寫圖片描述
如果讀入的x和y在一個集合裡,那麼就可以用維護的資訊算出x轉了一圈的時候y轉了幾圈,和讀入的資訊進行比對就可以判定是否發生矛盾。

這個資料範圍看起來好像很小的樣子。。但是如果它出上n-1個資訊,每次都是當齒輪i轉動1圈的時候齒輪i+1轉動100圈,那麼最後就會發現當齒輪1轉動一圈的時候齒輪n會轉動100n圈。。這樣的話就不能直接用int或者long long或者什麼類似的東西來維護加權並查集的dis了。。用分解質因數似乎是比較穩的方法,但是聽說用long double還是什麼類似的東西也能過?

程式碼

#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$個區間,