很是有趣的題目(指解法,不難,但很難想)c++
很是崇拜300iq,今天想作一套div1時看見了他出的這套題Grakn Forces 2020,就立馬開始補這套題,果真不出我所料,全是iq題(誤spa
m個set中有1-n的一些數,首先咱們能夠把一個數 j 從set i 中刪除,代價是 \(a[i]+b[j]\) ,至於爲何要刪除以後再說code
接着咱們對於每一個set i,\(\forall x,y \in i\),建邊\((x,y)\)並染色爲 \(i\) 。get
最後咱們定義\(Rainbow Cycle\)爲從某個節點x 出發,通過一個迴路可以從新回到x 且,迴路中的邊顏色兩兩各不相同it
問題是求出最小的刪除費用使得圖中沒有\(RainbowCycle\)class
核心:建圖跑最小生成樹test
建圖方式:數 \(j\) 在set \(i\) 裏就建一條邊\((n+i,j)\) ,這樣實際上每一個\(x,y\)在set裏的都已經聯通了,\(RainbowCycle\) 其實就變成了新圖裏的一條普通迴路總結
問題就很明顯了,一個沒有環的圖且刪邊費用最小就是最大生成樹sort
給\((x,y)\)邊染色爲\(z\),能夠增長一個新節點\(n+z(防止點重複)\) ,建兩條邊\((x,n+z),(n+z,y)\) 這樣方便對邊進行操做di
#include<bits/stdc++.h> using namespace std; #define ll long long const int N=2e5+10; int pre[N],tot=0; ll a[N],b[N]; struct E { int x,y; ll val; E(int x1,int y1,ll val1){ x=x1;y=y1;val=val1; }; E(){ x=y=val=0; }; }edge[2*N]; bool cmp(E x,E y) { return x.val>y.val; } int find(int x) { if(pre[x]==x) return x; else return pre[x]=find(pre[x]); } int merge(int x,int y) { int fx=find(x),fy=find(y); if(fx==fy) return 0; pre[fx]=fy; return 1; } int main() { int n,m; scanf("%d%d",&m,&n); for(int i=1;i<=m;i++) scanf("%lld",&a[i]); for(int j=1;j<=n;j++) scanf("%lld",&b[m+j]); for(int i=1;i<=m+n;i++) pre[i]=i; for(int i=1;i<=m;i++){ int x;scanf("%d",&x); for(int j=1;j<=x;j++){ int y;scanf("%d",&y); E cnt(i,m+y,a[i]+b[m+y]); edge[++tot]=cnt; } } sort(edge+1,edge+tot+1,cmp); ll res=0; for(int i=1;i<=tot;i++){ E cnt=edge[i]; int x=cnt.x,y=cnt.y; if(merge(x,y)){ continue; } else{ res+=cnt.val; //cout<<x<<' '<<y<<' '<<cnt.val<<endl; } } printf("%lld\n",res); }