hihocoder 1158 质数相关 dp

描述

两个数a和 b (a<b)被称为质数相关,是指a × p = b,这里p是一个质数。一个集合S被称为质数相关,是指S中存在两个质数相关的数,否则称S为质数无关。如{2, 8, 17}质数无关,但{2, 8, 16}, {3, 6}质数相关。现在给定一个集合S,问S的所有质数无关子集中,最大的子集的大小。

输入

第一行为一个数T,为数据组数。之后每组数据包含两行。

第一行为N,为集合S的大小。第二行为N个整数,表示集合内的数。

输出

对于每组数据输出一行,形如"Case #X: Y"。X为数据编号,从1开始,Y为最大的子集的大小。

数据范围

1 ≤ T ≤ 20

集合S内的数两两不同且范围在1到500000之间。

小数据

1 ≤ N ≤ 15

大数据

1 ≤ N ≤ 1000

样例输入

3
5
2 4 8 16 32
5
2 3 4 6 9
3
1 2 3

样例输出

Case #1: 3
Case #2: 3
Case #3: 2

#include<string.h>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<malloc.h>
#include<time.h>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<cstdlib>
#include<set>
#include<map>
using namespace std;
typedef  long long LL;
#define kmax 500000
LL prim[kmax+100],cnt,vit[kmax+100];
LL p[1010],n;
map<LL,LL>lk;
vector<LL>ko[kmax+100];
LL deep[1010],dp[1010];
void getprim(){
    cnt=0;
    memset(vit,0,sizeof(vit));
    for(LL i=2;i<=kmax;i++){
        if(!vit[i]){
            prim[++cnt]=i;
        }
         for(LL j=1;j<=cnt&&prim[j]*i<=kmax;j++){
              vit[prim[j]*i]=1;
              if(i%prim[j]==0) break;
            }
    }
}
void bfs(LL pos){
    int sum=0;
    queue<LL>tmp;
    while(!tmp.empty()) tmp.pop();
    tmp.push(p[pos]);
    while(!tmp.empty()){
        LL to=tmp.front(),pe=deep[lk[to]];tmp.pop();vit[to]=0;
        for(LL i=0;i<ko[to].size();i++){
            LL num=ko[to][i];
            if(vit[num]) {
                deep[lk[num]]=pe+1;
                tmp.push(num);
            }
        }
        sum++;
    }
}
LL getans(LL pos){
    if(ko[p[pos]].size()==0) return 1; // 这个数可以与任何一个数同时存在
    LL mmax=1;
    memset(deep,0,sizeof(deep));
    memset(dp,0,sizeof(dp));
    deep[pos]=1;
    bfs(pos);   // 求与 p[pos] 这个数有边的数 deep 值
    for(LL i=0;i<n;i++) if(deep[i]) dp[deep[i]]++,mmax=max(mmax,deep[i]);// 舒适化dp
    for(LL i=2;i<=mmax;i++) dp[i]=max(dp[i]+dp[i-2],dp[i-1]);
    return dp[mmax];
}
int main(){
    getprim();
    LL t,cas=0;cin>>t;
    while(t--){
        cin>>n;
        memset(vit,0,sizeof(vit));
        for(LL i=0;i<n;i++) cin>>p[i],ko[p[i]].clear(),vit[p[i]]=1;lk.clear();
        sort(p,p+n);
        for(LL i=0;i<n;i++) lk[p[i] ]=i;
        /* 给质数相关的数建边*/
        for(LL j=0;j<n;j++){
            for(LL k=1;k<=cnt;k++){
                if(1ll*p[j]*prim[k]>p[n-1]) break;
                if(vit[p[j]*prim[k]]){
                    ko[p[j] ].push_back(p[j]*prim[k] );
                    ko[p[j]*prim[k]].push_back(p[j]);
                }
            }
        }
        LL ans=0;
        for(LL i=0;i<n;i++)
        if(vit[p[i]]){
            ans+=getans(i);
        }
        printf("Case #%lld: %lld
",++cas,ans);
    }
}
原文地址:https://www.cnblogs.com/ainixu1314/p/4464031.html