problem:把一个可重集分成两个互异的不为空集合,两个集合里面的数相乘的gcd为1(将集合中所有元素的质因数没有交集)

solution:显然本题并不是那么容易啊!考场上想了好久。。

其实转化为上面的题意就简单多了,对于每一个元素分解质因数,就是在筛质数的时候记下每一个合数的最小质因子low[x],然后每一次不停的除low[x]

得到一个合数x',然后继续除low[x']即可,然后我们统计出含有每一个质因子的数有哪些(用一个二维vector),然后具有同种质因子的数必须放在同一个集合里面,

也就是说他们可以合并在一起,考虑并查集处理,就把每一个质因子把对应的数全部合并在一起,然后最后统计剩下的没有交集的最终不能再合并的互异块的个数tot

考虑用tot分成两个不同的非空集合,显然是2 tot -2,快速幂处理即可。

复杂度O(n log n)

code:

# include <bits/stdc++.h>
# define int long long
# define pow Pow
using namespace std;
const int M=1e6+10;
const int mo=1e9+7;
bool prime[M];
int low[M],a[M],f[M],n;
vector<int>r[M];
inline int read()
{int X=0,w=0; char c=0;while (!(c>='0'&&c<='9')) w|=c=='-',c=getchar();while (c>='0'&&c<='9') X=(X<<1)+(X<<3)+(c^48),c=getchar();return w?-X:X;
}
void getprime(int limit)
{memset(low,0,sizeof(low));memset(prime,true,sizeof(prime));for (int i=2;i<=limit;i++) {if (!prime[i]) continue;for (int j=i+i;j<=limit;j+=i) {if (low[j]==0) low[j]=i;prime[j]=false;}}
}
int father(int x)
{if (f[x]==x) return x;f[x]=father(f[x]);return f[x];
}
int calc(int x,int y)
{int fx=father(x),fy=father(y);f[fx]=fy;
}
void solve(int id)
{int num=a[id];while (low[num]) {r[low[num]].push_back(id);int tmp=low[num];while (num%tmp==0) num/=tmp;}r[num].push_back(id);
}
int pow(int x,int n)
{int ans=1;while (n) {if (n&1) ans=ans*x%mo;x=x*x%mo;n>>=1;}return ans%mo;
}
signed main()
{int T=read();while (T--) {n=read();int MAX=0;for (int i=1;i<=n;i++) {a[i]=read(); f[i]=i;MAX=max(MAX,a[i]);}getprime(MAX);for (int i=1;i<=M;i++) r[i].clear();for (int i=1;i<=n;i++) solve(i);for (int i=2;i<=M;i++) {if (r[i].size()==0) continue;int k=r[i][0];for (int j=1;j<r[i].size();j++)  calc(k,r[i][j]);}int ret=0;for (int i=1;i<=n;i++) if (f[i]==i) ret++;printf("%lld\n",(pow(2,ret)%mo-2+mo)%mo); }return 0;
}

sol:分成两组然后每一组的人都互相认识,显然想到对每一个联通块01染色分成不同的集合

对于每一个联通块统计出0的块的个数1的块的个数,显然0或者1的个数为n/2最好才会使 calc(i)+calc(n-i)最小

其中calc(x)=x(x-1)/2,

由于每一个块我们只能有1或者0,那么设f[i][j]表示前i个块,选择0或者1的块为j是否可能

转移的话就是

f[i][j]|=f[i-1][j-a[i].cnt0]|f[i-1][j-a[i].cnt1]

然后j从n/2向左枚举然后找到若f[n][j]合法

那么最小化 clac(j)+calc(n-j)即可

code:

# include <bits/stdc++.h>
# define int long long
using namespace std;
const int MAXN=1005;
int mp[MAXN][MAXN],n,m,col[MAXN];
bool f[MAXN][MAXN];
int cnt0,cnt1;
int o;
struct rec{ int cnt0,cnt1;}b[MAXN];
void dfs(int u,int fa,int c)
{col[u]=c;//printf("%d ; col=%d\n",u,col[u]);if (c==0) cnt0++; else cnt1++;for (int v=1;v<=n;v++) {if (mp[u][v]==0) continue;if (col[v]!=-1) {if (col[v]!=c^1) { puts("-1"); exit(0);} else continue;}  dfs(v,u,c^1);  }
}
int calc(int x){ return x*(x-1)/2;}
signed main()
{scanf("%lld%lld",&n,&m);for (int i=1;i<=n;i++)for (int j=1;j<=n;j++) if (i==j) mp[i][j]=false;else mp[i][j]=true;while (m--) {int u,v; scanf("%lld%lld",&u,&v);mp[u][v]=mp[v][u]=false;}   memset(col,-1,sizeof(col));for (int i=1;i<=n;i++) if (col[i]==-1) {cnt0=cnt1=0;dfs(i,-1,1);b[++o].cnt1=cnt1;b[++o].cnt0=cnt0;}//f[i][j]前i个集合,到达A中有j个是否成立//f[i][j]|=f[i-1][j-b[i].cnt0]|f[i-1][j-b[i].cnt1]memset(f,false,sizeof(f));f[1][b[1].cnt1]=f[1][b[1].cnt0]=true;for (int i=2;i<=n;i++) for (int j=1;j<=n;j++) f[i][j]=f[i][j]|f[i-1][j-b[i].cnt0]|f[i-1][j-b[i].cnt1];int Ans=n*n*2;for (int i=0;i<=n;i++)if (f[n][i]) Ans=min(Ans,calc(i)+calc(n-i));cout<<Ans<<endl; return 0;
}

转载于:https://www.cnblogs.com/ljc20020730/p/9899524.html

HGOI 20181103 题解相关推荐

  1. HGOI 20190709 题解

    Problem A 紫色激情 一个序列$\{a_n\}$,求出方差最大的子序列. 其中方差 [l,r] 的定义是$S^2 = \frac{1}{n} \sum\limits_{i=l}^{r} (x_ ...

  2. HGOI 20190711 题解

    Problem A 矩阵第K小数 给定一个$n \times m$的矩阵,位置$A_{i,j}  = i\times j$, 给出$Q$个询问,每一次查询矩阵中第$Q_i$小的数是多少. 对于100% ...

  3. [JS][dfs]题解 | #迷宫问题#

    题解 | #迷宫问题# 题目链接 迷宫问题 题目描述 定义一个二维数组 N*M ,如 5 × 5 数组下所示: int maze[5][5] = { 0, 1, 0, 0, 0, 0, 1, 1, 1 ...

  4. [JS][dp]题解 | #打家劫舍(一)#

    题解 | #打家劫舍(一)# 题目链接 打家劫舍(一) 题目描述 描述 你是一个经验丰富的小偷,准备偷沿街的一排房间,每个房间都存有一定的现金,为了防止被发现,你不能偷相邻的两家,即,如果偷了第一家, ...

  5. [JS]题解 | #魔法数字#

    题解 | #魔法数字# 题目链接 魔法数字 题目描述 牛妹给牛牛写了一个数字n,然后又给自己写了一个数字m,她希望牛牛能执行最少的操作将他的数字转化成自己的. 操作共有三种,如下: 在当前数字的基础上 ...

  6. [JS]题解 | #岛屿数量#

    题解 | #岛屿数量# 题目链接 岛屿数量 题目描述 时间限制:1秒 空间限制:256M 描述 给一个01矩阵,1代表是陆地,0代表海洋, 如果两个1相邻,那么这两个1属于同一个岛.我们只考虑上下左右 ...

  7. [JS] 题解:提取不重复的整数

    题解:提取不重复的整数 https://www.nowcoder.com/practice/253986e66d114d378ae8de2e6c4577c1 时间限制:1秒 空间限制:32M 描述 输 ...

  8. 洛谷-题解 P2672 【推销员】

    独门思路!链表加优先队列! 这题一望,贪心是跑不掉了,但是我贪心并不好,所以想到了一个复杂一些但思路更保稳的做法 思路: 1 因为是离线操作,所以我们可以倒着求,先求x=n的情况,因为那样直接就知道了 ...

  9. [洛谷1383]高级打字机 题解

    题解 这道题一看就珂以用主席树啊 这是一道神奇的题目,那么我们先敲一个主席树,然后维护一个数组len,表示下一次应该在len + 1插入, 之后对于T操作,在上一个版本的len + 1上直接执行插入 ...

最新文章

  1. Ubuntu 18安装 chrome
  2. android摄像头预览功能,android通过camera和surfaceview选择摄像头并即时预览
  3. 中南月赛 1313: ZZY的宠物
  4. sys_brk分析 linux1.2.0版本,linux内存管理之sys_brk实现分析(续)
  5. 从LeNet到AlexNet
  6. 【Unity Shader】---UnityShader 提供的CG/HLSL语义
  7. Saga分布式事务解决方案与实践
  8. 计算机硬盘使用率,硬盘占用率和速度
  9. MSP430开发环境配置
  10. JAVANBA论坛系统计算机毕业设计Mybatis+系统+数据库+调试部署
  11. (三) SiamRPN从论文角度介绍
  12. 365 水壶问题(递归、数学-裴蜀定理)
  13. 新入手Seagate希捷1TB移动硬盘1t USB3.0一个
  14. 高德地图开发(二)加载瓦片数据
  15. 单片机程序运行在哪里
  16. 看电影用这个小程序,爆米花钱肯定给你省出来!
  17. 希捷硬盘升级固件方法
  18. 计算机制图基本知识6,机械制图的基础知识,看完小白也懂了!
  19. java版 SpringCloud 之Eclipse 教程
  20. 下载磁力链接的软件推荐

热门文章

  1. Vue_(组件通讯)动态组件结合keep-alive
  2. vue中的config配置
  3. 【Java面试题】39 Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?...
  4. canvas之webgl的浏览器开启方式
  5. Java--缓存热点数据,最近最少使用算法
  6. write() ,read();
  7. 算法——计数排序与快速排序
  8. Python 数据类型及其用法
  9. linux编辑器翻页,Linux的Vim编辑器的使用Part1:输入模式、移动光标和翻页
  10. 陈硕智能指针线程安全_C++ 创建线程的方法