zoukankan      html  css  js  c++  java
  • 洛谷P1978 集合 [2017年6月计划 数论08]

    P1978 集合

    题目描述

    集合是数学中的一个概念,用通俗的话来讲就是:一大堆数在一起就构成了集合。集合有如

    下的特性:

    •无序性:任一个集合中,每个元素的地位都是相同的,元素之间是无序的。

    •互异性:一个集合中,任何两个元素都认为是不相同的,即每个元素只能出现一次。

    •确定性:给定一个集合,任给一个元素,该元素或者属于或者不属于该集合,二者必居

    其一,不允许有模棱两可的情况出现。

    例如 A = {1, 2, 3} 就是一个集合。我们可以知道, 1 属于 A ,即 1 ∈ A ; 4 不属于 A ,

    即 4 ∉ A 。一个集合的大小,就是其中元素的个数。

    现在定义一个特殊的 k-集合,要求满足:

    •集合的所有特性

    •对任意一个该集合内的元素 x ,不存在一个数 y ,使得 y = kx 并且 y 属于该集合。即

    集合中的任意一个数,它乘以 k 之后的数都不在这个集合内

    给你一个由 n 个不同的数组成的集合,请你从这个集合中找出一个最大的 k-集合。

    输入输出格式

    输入格式:

    第 1 行:两个整数: n 和 k

    第 2 行:n 个整数: a[i] 表示给定的集合

    输出格式:

    第 1 行:一个整数: ans 表示最大的 k-集合的大小

    输入输出样例

    输入样例#1:
    6 2	
    2 3 6 5 4 10
    
    输出样例#1:
    3

    说明

    提示:在样例所给集合中,找出的最大的 2-集合为 {4, 5, 6}

    •对于 30% 的数据: n, k ≤ 100

    •对于 40% 的数据: a[i] ≤ 231-1

    •对于 70% 的数据: n, k ≤ 5000

    •对于 100% 的数据: n, k ≤ 105, a[i] ≤ 263-1

    Solution

    tips:最近做题总是忘记longlong或者空间开小。。。郁闷

    这道题可以排序后从大到小排序,对于每个数x,若k | x,二分找x / k,标记为不能选

    由于是从大往小找,可知当前x是否选取影响不到比它大的数

    其实从最小开始选也可以

    证明:

    对于奇数个连续的k的倍数(即 k * a, k * (a + 1), k * (a + 2)...)  可知从非最大(或最小)开始选一定不优于从最大开始选

    对于偶数个连续的k的倍数(即 k * a, k * (a + 1),k * (a + 2),k * (a + 3).。。)   无论从哪一个开始选都等价

    因此从最大(或最小)的开始选一定最优

    但我们从最大开始,因为找的时候会做除法,不会爆long long范围

    从最小开始需要做一些防止爆long long的处理

     

    Code

    从小开始找的代码:

    #include <bits/stdc++.h>
    inline void read(long long &x){x = 0;char ch = getchar();while(ch > '9' || ch < '0'){ch = getchar();}while(ch >= '0' && ch <= '9')x = x * 10 + ch - '0', ch = getchar();}
    inline long long max(long long a, long long b){return a > b ? a : b;}
    inline long long min(long long a, long long b){return a > b ? b : a;}
    inline void swap(long long &a, long long &b){long long tmp = a;a = b;b = tmp;}
    const long long INF = 0xfffffffffffffff;
    
    const int MAXN = 100000 + 10;
    const int MAXK = 100000 + 10;
    
    long long num[MAXN],n,k;
    bool b[MAXN];//记录哪一些数不能加入,true表示不能加 
    
    long long erfen(int l, int r, long long p)
    {
    	long long mid;
    	while(l < r)
    	{
    		mid = l + ((r - l) >> 1);
    		if(num[mid] >= p)r = mid;
    		else l = mid + 1;
    	}
    	return l;
    }
    
    long long ans;
    
    int main()
    {
     	read(n);read(k);
     	for(int i = 1;i <= n;i ++)
     	{
     		read(num[i]);
     	}
     	std::sort(num + 1, num + 1 + n);
     	float ma = (float)num[n] / (float)k;
     	for(long long i = 1;i <= n;i ++)
     	{
     		if(!b[i])
    		{
    			ans ++;
    			if(num[i] > ma)continue;
    			long long tmp = erfen(i, n, num[i] * k);
    			if(num[tmp]  == num[i] * k)
    				b[tmp] = true; 
    		} 
     	}
     	printf("%d", ans);
    	return 0;
    }
    

    从大开始找的代码:

    #include <bits/stdc++.h>
    inline void read(long long &x){x = 0;char ch = getchar();while(ch > '9' || ch < '0'){ch = getchar();}while(ch >= '0' && ch <= '9')x = x * 10 + ch - '0', ch = getchar();}
    inline long long max(long long a, long long b){return a > b ? a : b;}
    inline long long min(long long a, long long b){return a > b ? b : a;}
    inline void swap(long long &a, long long &b){long long tmp = a;a = b;b = tmp;}
    const long long INF = 0xfffffffffffffff;
    
    const int MAXN = 100000 + 10;
    const int MAXK = 100000 + 10;
    
    long long num[MAXN],n,k;
    bool b[MAXN];//记录哪一些数不能加入,true表示不能加 
    
    long long erfen(int l, int r, long long p)
    {
        long long mid;
        while(l < r)
        {
            mid = l + ((r - l) >> 1);
            if(num[mid] >= p)r = mid;
            else l = mid + 1;
        }
        return l;
    }
    
    long long ans;
    
    int main()
    {
         read(n);read(k);
         for(int i = 1;i <= n;i ++)
         {
             read(num[i]);
         }
         std::sort(num + 1, num + 1 + n);
         for(long long i = n;i >= 1;i --)
         {
             if(!b[i])
            {
                ans ++;
                if(num[i] % k == 0)
                {
                    long long tmp = erfen(1, i, num[i] / k);
                    if(num[tmp] * k == num[i])
                        b[tmp] = true; 
                }
            } 
         }
         printf("%d", ans);
        return 0;
    }
    
  • 相关阅读:
    AOP从静态代理到动态代理 Emit实现
    云计算仿真工具CloudSim介绍和使用
    SSH框架中配置log4j的方法
    SSH常见面试题
    第一章
    shell 生成目录的树状视图、生成文件及子目录的汇总信息
    shell拼写检查,利用Linux字典
    SHELL:多文件的重命名和移动
    sort
    tr1
  • 原文地址:https://www.cnblogs.com/huibixiaoxing/p/7015597.html
Copyright © 2011-2022 走看看