CodeForces - 274A - k-Multiple Free Set

先上题目

k-Multiple Free Set

time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

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.

Input

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.

Output

On the only line of the output print the size of the largest k-multiple free subset of {a1, a2, ..., an}.

Sample test(s)
Input
6 2
2 3 6 5 4 10
Output
3
Note

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 }
274A

 

posted @ 2013-08-01 19:54  海拉鲁的林克  阅读(653)  评论(0编辑  收藏  举报