zoukankan      html  css  js  c++  java
  • 钦点

    题目

    钦点

    题意

    给定n个数,两个数之间有边当且仅当两个数的(gcd)为合数。求删去一个节点后,最大连通块的大小的最小值是多少。

    题解

    对没一个可以被分解为两个素数的乘积的数建虚点。
    对于一个点, 向他的权值的因数中可以被分解为两个素数的乘积的数的虚点连边。
    于是欧拉筛预处理每个数的最小质因子, 然后对于每个点的权值, (O({因子个数}^2))枚举连边即可, 注意处理平方数。
    注意虚点不能被计入答案。

    显然是去掉最大连通块中的一个割点。
    于是在最大连通块上求割点,对于每个割点,求出去掉它之后的最大连通块大小。
    最后答案和次大联通块的大小取(max)

    代码

    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    
    
    const int N = 10000010, M = 20000010;
    
    const int Lim = 10000000;
    
    
    struct edge
    {
    	int from, to;
    	edge() { }
    	edge(int _1, int _2) : from(_1), to(_2) { }
    } edges[M];
    
    int head[N], nxt[M], tot;
    
    inline void init()
    {
    	memset(head, -1, sizeof(head));
    	tot = 0;
    }
    
    inline void add_edge(int x, int y)
    {
    	edges[tot] = edge(x, y);
    	nxt[tot] = head[x];
    	head[x] = tot++;
    	edges[tot] = edge(y, x);
    	nxt[tot] = head[y];
    	head[y] = tot++;
    }
    
    
    int n;
    
    int w[Lim / 100 + 10];
    
    
    int pri[Lim / 5 + 10], rec[Lim + 10], total;
    bool ispri[Lim + 10];
    
    void pre()
    {
    	ispri[1] = 1;
    	for (int i = 2; i <= Lim; i++)
    	{
    		if (!ispri[i]) { pri[++total] = i; rec[i] = i; }
    		for (int j = 1; j <= total && pri[j] * i <= Lim; j++)
    		{
    			ispri[i * pri[j]] = 1;
    			rec[i * pri[j]] = pri[j];
    			if (i % pri[j] == 0) break;
    		}
    	}
    }
    
    
    bool vis[N];
    
    int dfs(int x)
    {
    	vis[x] = 1;
    	int siz = (x <= n ? 1 : 0);
    	for (int i = head[x]; ~i; i = nxt[i])
    	{
    		edge & e = edges[i];
    		if (!vis[e.to])
    			siz += dfs(e.to);
    	}
    	return siz;
    }
    
    
    int low[N], dfn[N], dfs_clock;
    
    int siz[N];
    
    int all;
    
    int Ans;
    
    bool bo[N];
    
    void Tarjan(int x, int fa)
    {
    	low[x] = dfn[x] = ++dfs_clock;
    	siz[x] = (x <= n ? 1 : 0);
    	int num = (x <= n ? 1 : 0), maxv = 0;
    	
    	int s = 0;
    	
    	for (int i = head[x]; ~i; i = nxt[i])
    	{
    		edge & e = edges[i];
    		if (e.to != fa)
    		{
    			s++;
    			if (!dfn[e.to])
    			{
    				Tarjan(e.to, x);
    				siz[x] += siz[e.to];
    				low[x] = min(low[x], low[e.to]);
    				if (low[e.to] >= dfn[x])
    				{
    					bo[x] = 1;
    					num += siz[e.to];
    					maxv = max(maxv, siz[e.to]);
    				}
    			}
    			else
    				low[x] = min(low[x], dfn[e.to]);
    		}
    	}
    	maxv = max(maxv, all - num);
    	
    	if (!fa && s <= 1) bo[x] = 0;
    	if (x <= n && bo[x]) Ans = min(Ans, maxv);
    }
    
    
    vector<int> vec[Lim / 100 + 10];
    
    int id[Lim + 10];
    
    
    int main()
    {
    	pre();
    	
    	int T;
    	
    	scanf("%d", &T);
    	
    	while (T--)
    	{
    		scanf("%d", &n);
    		
    		init();
    		
    		int cid = n;
    		
    		for (int i = 1; i <= n; i++)
    			scanf("%d", &w[i]);
    		
    		for (int i = 1; i <= n; i++)
    		{
    			int x = w[i];
    			int tot = 0;
    			static int num[110], sum[110];
    			while (x > 1)
    			{
    				if (num[tot] != rec[x])
    					num[++tot] = rec[x], sum[tot] = 0;
    				sum[tot]++;
    				x /= rec[x];
    			}
    			vec[i].clear();
    			for (int j = 1; j <= tot; j++)
    			{
    				for (int k = j+1; k <= tot; k++)
    				{
    					if (num[j] * num[k] > Lim) continue;
    					vec[i].push_back(num[j] * num[k]);
    					if (!id[num[j] * num[k]]) id[num[j] * num[k]] = ++cid;
    					add_edge(i, id[num[j] * num[k]]);
    				}
    				if (sum[j] > 1)
    				{
    					if (num[j] * num[j] > Lim) continue;
    					vec[i].push_back(num[j] * num[j]);
    					if (!id[num[j] * num[j]]) id[num[j] * num[j]] = ++cid;
    					add_edge(i, id[num[j] * num[j]]);
    				}
    			}
    		}
    		
    		
    		int num1 = 0, num2 = 0;
    		
    		for (int i = 1; i <= cid; i++)
    			if (!vis[i])
    			{
    				all = dfs(i);
    				if (all >= num1)
    				{
    					if (all > num1) Ans = all - 1;
    					num2 = num1, num1 = all;
    				}
    				else num2 = max(num2, all);
    				if (all == num1) Tarjan(i, 0);
    			}
    		
    		printf("%d
    ", max(num2, Ans));
    		
    		memset(low, 0, sizeof(int) * (cid + 1));
    		memset(dfn, 0, sizeof(int) * (cid + 1));
    		memset(vis, 0, sizeof(int) * (cid + 1));
    		memset(siz, 0, sizeof(int) * (cid + 1));
    		memset(bo, 0, sizeof(int) * (cid + 1));
    		dfs_clock =  0;
    		Ans = 0;
    		all = 0;
    		for (int i = 1; i <= n; i++)
    		{	for (auto u : vec[i]) id[u] = 0;
    			vec[i].clear();
    		}
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    权限管理
    书城项目第五阶段---book表的curd
    大话设计模式学习
    数据绑定流程分析
    GO 解决使用bee工具,报 bash: bee: command not found
    VScode插件:Todo Tree
    ant design pro如何实现分步表单时,返回上一步值依然被保存
    React开发流程
    为什么函数式组件没有生命周期?
    html2canvas@^1.0.0-rc.1
  • 原文地址:https://www.cnblogs.com/2016gdgzoi509/p/10023025.html
Copyright © 2011-2022 走看看