CodeForces - 274A - k-Multiple Free Set
先上题目
k-Multiple Free Set
A k-multiple free set is a set of integers where there is no pair of integers where one is equal to another integer multiplied by k. That is, there are no two integers x and y (x < y) from the set, such that y = x·k.
You're given a set of n distinct positive integers. Your task is to find the size of it's largest k-multiple free subset.
The first line of the input contains two integers n and k (1 ≤ n ≤ 105, 1 ≤ k ≤ 109). The next line contains a list of n distinct positive integers a1, a2, ..., an (1 ≤ ai ≤ 109).
All the numbers in the lines are separated by single spaces.
On the only line of the output print the size of the largest k-multiple free subset of {a1, a2, ..., an}.
6 2
2 3 6 5 4 10
3
In the sample input one of the possible maximum 2-multiple free subsets is {4, 5, 6}.
题意是给你一堆数,每个数只出现了一次,以及一个正整数倍数k,定义一种子集里面的x<y且x*k!=y,这种子集元素最多的时候个数有多大。
这一题的分类暂时也不知道该分为什么,这种题好像曾经遇到过,可是当时好像也没有做出来,今天这一题感觉有点像是水过去的。
做法是先对这些数进行排序,然后找出每一个数的k被在不在这些数里面,如果在,将那个数的位置记录下来,然后就从头开始扫描,遇到一个数,如果没有访问过,就访问它,看看的k倍,k*k倍,k*k*k倍···存不存在,并记录下最终从这个数按照访问它的这些倍数的个数,同时没访问完一个数,标记它已经被访问完,下次就不需要被访问了。
那么为什么要这样做呢,解释如下:当一个数它不是某个数的k倍,同时它的k倍也不存在,那么在构成子集的时候,这个数就一定要选上;如果这个数是某个数的k倍,或者它的k倍在这些数里面的话,那它们的关系就可以用一条链来形容,因为每一个数至于它的k倍和它除以k的那个数有关,在这条链上面的其他数都与它没有关系,那我们只需要取这条链中相隔的数,就可以达到取最多数的目的。那么如果这条链的长度是偶数,那就去一半,如果是奇数,那就去平分后+1这么多的数目。
这一题的数据量不大,可以开一个布尔数组标记某个值访问了没有,如果数据更加大,应该就要用set了。
同时这一题的每一个数都只会出现一次,所以可以用这种方法贪心,如果是这个数出现不止一次的话,就不可以这样做了,那需要用dp。
上代码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 #define LL long long 5 #define MAX (100000+10) 6 using namespace std; 7 8 9 typedef struct 10 { 11 LL d; 12 int m; 13 }S; 14 15 S s[MAX]; 16 int c[MAX]; 17 bool f[MAX]; 18 19 bool cmp(S x,S y){return x.d<y.d;} 20 21 int finds(int l,int r,LL t) 22 { 23 while(l<=r) 24 { 25 int mid=(l+r)>>1; 26 if(s[mid].d<t) l=mid+1; 27 else r=mid-1; 28 } 29 return l; 30 } 31 32 void deal(int t) 33 { 34 int i; 35 c[t]=1; 36 for(i=s[t].m;i!=-1;i=s[i].m) 37 { 38 c[t]++; 39 f[i]=1; 40 } 41 } 42 43 void check(int n) 44 { 45 int i; 46 memset(c,0,sizeof(c)); 47 memset(f,0,sizeof(f)); 48 for(i=0;i<n;i++) 49 { 50 if(!f[i]) deal(i); 51 } 52 } 53 54 int main() 55 { 56 int i,n; 57 LL k,tot,M; 58 //freopen("data.txt","r",stdin); 59 scanf("%d %lld",&n,&k); 60 M=-1; 61 for(i=0;i<n;i++) 62 { 63 scanf("%lld",&s[i].d); 64 M=s[i].d>M ? s[i].d : M; 65 } 66 sort(s,s+n,cmp); 67 //s[n].d=M+2; 68 //s[n].m=-1; 69 for(i=0;i<n;i++) 70 { 71 LL t=s[i].d*k; 72 s[i].m=finds(i+1,n,t); 73 if(t!=s[s[i].m].d) s[i].m=-1; 74 } 75 check(n); 76 tot=0; 77 for(i=0;i<n;i++) 78 { 79 if(!f[i]) tot+=((c[i]+1)>>1); 80 } 81 printf("%lld",tot); 82 return 0; 83 }