「LibreOJ β Round #4」子集

本文解析洛谷526题,介绍一种利用最大点独立集算法解决的问题:从给定序列中选出最多数量的元素,使得任意两元素满足特定的数学条件。通过奇偶分类、图论建模及匈牙利算法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://loj.ac/problem/526
题目描述

qmqmqm有一个长为 n 的数列 a1,a2,,an,你需要选择集合{1,2,,n}的一个子集,使得这个子集中任意两个元素 i,j 均满足条件 gcd(ai,aj)×gcd(ai+1,aj+1)≠1,其中gcd(i,j)表示最大公约数,且这个子集的元素个数是所有满足上述条件的子集中最多的。输出这个子集的元素个数。

输入格式

输入的第一行包含一个正整数nnn。 随后nnn行,每行一个正整数aia_iai​​。

输出格式

输出一个整数代表符合条件的元素最多的子集的元素个数。

样例
样例输入1
4
4
6
1
9
样例输出1
3
样例解释

选择的子集为{1,2,4}\{1,2,4\}{1,2,4}。

样例输入2
41
71
3
5
50
75
2
19
47
88
95
92
110
111
117
58
124
130
57
129
168
161
29
39
206
79
10
142
107
209
210
222
221
223
242
104
264
265
202
279
314
315
样例输出2
22


奇数和奇数、偶数和偶数一定可以选在一起
所以对于不满足条件的奇数和偶数,连边
求最大点独立集
即点数-匹配数

#include<cstdio>
#include<iostream>
#define N 501
using namespace std;
typedef long long LL;
int n;
LL a[N],b[N];
bool g[N][N],vis[N];
int match[N];
void read(int &x)
{
    x=0; int f=1; char c=getchar();
    while(!isdigit(c)) { if(c=='-') f=-1;  c=getchar(); }
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    x*=f;
}
void read(LL &x)
{
    x=0; int f=1; char c=getchar();
    while(!isdigit(c)) { if(c=='-') f=-1;  c=getchar(); }
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    x*=f;
}
inline LL gcd(LL p,LL q) { return !q ? p : gcd(q,p%q); }
bool go(int now)
{
    for(int i=1;i<=b[0];i++)
    {
        if(vis[i] || !g[now][i]) continue;
        vis[i]=true;
        if(!match[i] || go(match[i]))
        {
            match[i]=now;
            return true;
        }
    }
    return false;
}
int main()
{
    read(n);
    LL x;
    for(int i=1;i<=n;i++)
    {
        read(x);
        (x&1 ? a[++a[0]] : b[++b[0]])=x;
    }
    for(int i=1;i<=a[0];i++)
        for(int j=1;j<=b[0];j++)
            if(gcd(a[i],b[j])==1 && gcd(a[i]+1,b[j]+1)==1) g[i][j]=true;
    int sum=0;
    for(int i=1;i<=a[0];i++)
    {
        fill(vis+1,vis+b[0]+1,0);
        if(go(i)) sum++;
    }
    printf("%d",n-sum); 
} 

 



转载于:https://www.cnblogs.com/TheRoadToTheGold/p/7468782.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值