「LibreOJ β Round #4」子集

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