zoukankan      html  css  js  c++  java
  • ABC210: E


    ABC210: E - Ring MST #最小生成树# #数学#

    题目

    大意:给定(n)个点(编号(0)~(n-1)),(m)种无向边,第(i)种边可以连接点(x,(x+a_i)mod n(0le xle n-1))用一次的花费为(c_i),求将图变成一个连通块的最小花费
    在这里插入图片描述

    思路

    不难想到,这题是最小生成树,而且是(Kruskal)(边数较小,点数巨大)
    不管三七二十一,先把边按(c_i)单调递增排序.
    再想想,费用越小的边,肯定用得越多越好(在能连接不同连通块的前提下).如果我们知道,在已经连上费用更小的边的情况下,一种边在有意义(能连接两个不同的连通块)的前提下最多能用多少次,那这题不就A了吗?
    难点就在这里.
    我们设加上前(i)种边后(已排序),图中最少有(x_i)个连通块.
    特别地,(x_0=N),显然,答案就是:

    [sum ^m_{i=1}c_icdot (x_{i-1}-x_{i}) ]

    (x_n>1)时,无解,输出-1
    所以如何求(x)?
    根据题意,在加入前(i)种边后,点(w)(u)在同一个连通块内,当且仅当:存在正整数序列(k_1,k_2,k_3,cdots k_i),使得(w=(u+sum ^i_{j=1}k_icdot a_i)mod n),即(w=u+sum ^i_{j=1}k_icdot a_i+k_0cdot n(k_0in ))
    变换一下:

    [k_0cdot n+k_1cdot a_1+k_2cdot a_2+cdots+k_icdot a_i+u-w=0 ]

    其中,(n,a)已知,(k)都是整数但未知,判断是否存在一组合法的(k),这是什么?斐蜀定理!!!
    所以,(w,u)连通,当且仅当,(gcd(n,a_1,a_2,cdots,a_i)|u-w),((x|y)表示(x)能整除(y))
    (wequiv u(mod gcd(n,a_1,a_2,cdots,a_i))),余数有(0,1,2,cdotsgcd(n,a_1,a_2,cdots,a_i)-1)(gcd(n,a_1,a_2,cdots,a_i))种,所以共(gcd(n,a_1,a_2,cdots,a_i))个连通块
    所以(x_i= gcd(n,a_1,a_2,cdots,a_i))
    所以我们就做完了
    官方题解:
    在这里插入图片描述

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <algorithm>
    using namespace std;
    int read() {
    	int re = 0;
    	char c = getchar();
    	bool negt = false;
    	while(c < '0' || c > '9')
    		negt |= (c == '-') , c = getchar();
    	while(c >= '0' && c <= '9')
    		re = (re << 1) + (re << 3) + c - '0' , c =getchar();
    	return negt ? -re : re;
    }
    const int M = 100010;
    int gcd(int a , int b) {
    	return b == 0 ? a : gcd(b , a % b);
    }
    
    struct node {
    	int a , c;
    }ed[M];
    bool cmp(node a , node b) {
    	return a.c < b.c;
    }
    
    int n , m;
    int x[M];
    
    signed main() {
    	n = read() , m = read();
    	for(int i = 1 ; i <= m ; i++)
    		ed[i].a = read() , ed[i].c = read();
    	
    	sort(ed + 1 , ed + m + 1 , cmp);
    
    	x[0] = n;
    	for(int i = 1 ; i <= m ; i++)
    		x[i] = gcd(x[i - 1] , ed[i].a);
    
    	if(x[m] > 1)
    		puts("-1");
    	else {
    		long long ans = 0;
    		for(int i = 1 ; i <= m ; i++)
    			ans += 1ll * (x[i - 1] - x[i]) * ed[i].c;
    		cout <<ans;
    	}
    	return 0;
    }
    
  • 相关阅读:
    png图片透明在ie6中显示问题
    DIV背景图片在Firefox下不显示,IE下正常
    整理:兼容 IE、Firefox、Opera和Safari
    IE6背景消失问题
    鼠标悬停换图片或背景
    网站团队组建方案
    CSS兼容IE6,IE7,FF的技巧
    打造MySQL版的最新IP数据库
    域名判断后跳转——PHP跳转代码_ASP跳转代码_JS跳转代码
    IE6文字消失、背景圖消失之謎
  • 原文地址:https://www.cnblogs.com/dream1024/p/15041890.html
Copyright © 2011-2022 走看看