首页 > 试题广场 >

k倍多重正整数集合

[编程题]k倍多重正整数集合
  • 热度指数:1407 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 128M,其他语言256M
  • 算法知识视频讲解

k倍多重正整数集合的定义是:在一个多重集合(元素可以重复)中,不存在一个正整数是另一个正整数的k倍。

现在小Mn个正整数,你可以选择其中一些数构成k倍多重正整数集合。请求出最多能选出多少数来构成它。


输入描述:
第一行有两个整数n, k(1 <= n <= 10^5, 1 <= k <= 10^9)。

接下来一行有n个正整数a1, a2, ..., an (1 <= ai <= 10^9)。


输出描述:
最多能选出多少数构成k倍多重正整数集合。
示例1

输入

6 2
2 3 6 5 4 10

输出

3

说明

第一个样例中,我们选择2,3,5即可满足要求,因为k == 2,不存在一个数是另一个数的两倍。
示例2

输入

2 2
2 2

输出

2

说明

第二个样例中,我们选择2,2即可满足要求,因为k == 2,2也不是2的两倍,注意多重集合元素可以重复。
/*
找规律
*/
#include <bits/stdc++.h>
using namespace std;

int main()
{
//  freopen("input.txt","r",stdin);
    int n, k, i, x, t_min;
    cin >> n >> k;
    map<int, int> dic;
    for(i = 0; i < n; i++) {
        cin >> x;
        dic[x]++;
    }
    if(k == 1) {
        cout << dic.size() << endl;
        return 0;
    }
    for(auto it = dic.begin(); it != dic.end(); it++) {
        if(dic.find(it->first * k) == dic.end()) continue;
        if(it->second < 1 || dic[it->first * k] < 1) continue;
        t_min = min(it->second, dic[it->first * k]);
        n -= t_min;
        it->second -= t_min;
        dic[it->first * k] -= t_min;
    }
    cout << n << endl;
}

发表于 2019-07-17 10:48:34 回复(0)
#include <bits/stdc++.h>
using namespace std;

int main(){
    int n,k,x,t;
    cin>>n>>k;
    map<int, int> M;
    for(int i=0;i<n;i++){
        cin>>x;
        M[x]++;
    }
    if(k==1){
        cout<<M.size()<<endl;
    }else{
        for(map<int,int>::iterator it=M.begin();it!=M.end();it++){
            x = (it->first)*k;
            if(M.find(x)==M.end())
                continue;
            if(it->second==0 || M[x]==0)
                continue;
            t = min(it->second, M[x]);
            n -= t;
            M[x] -= t;
            it->second -= t;
        }
        cout<<n<<endl;
    }
    return 0;
}

发表于 2019-08-15 12:09:00 回复(0)
using System;
using System.Collections.Generic;
public class Program {
    public static void Main() {
        string line;
        while ((line = System.Console.ReadLine ()) != null) { // 注意 while 处理多个 case
            string[] tokens = line.Split();
            long n = long.Parse(tokens[0]);
            long k = long.Parse(tokens[1]);
            SortedSet<long> list = new SortedSet<long>();
            Dictionary<long, int> dic = new Dictionary<long,int>();
            string[] tokens1 = System.Console.ReadLine ().Split();
            int max = 0;
            for(int i=0;i<n;i++)
            {
                int num = int.Parse(tokens1[i]);
                if(dic.ContainsKey(num))
                {
                    dic[num]++;
                }
                else
                {
                    dic.Add(num, 1);
                    list.Add(num);
                    if(num > max)
                        max = num;
                }
            }
            if(k==1)
            {
                Console.WriteLine(dic.Count);
            }
            //这个原理是 :
            //对于存在倍数的两种数 a 和 b,假设a有 x1个,b有x2个,x1 < x2,b = a * k
            //虽然我们不能确定最后选a还是选b,但是我们可以确定的是,对于x1个a和x1个b,他们一定只会留下x1个数
            //所以 n-=x1, 然后剩下 x2-x1个b再继续到后面去判断
            else
            {
                foreach(long key in list)
                {
                    if(dic.ContainsKey(key*k))
                    {
                        if(dic[key*k] == max)
                            continue;
                        int mi = Math.Min(dic[key], dic[key*k]);
                        n -= mi;
                        dic[key] -= mi;
                        dic[key*k] -= mi;                            
                    }
                }
                Console.WriteLine(n);
            }
        }
    }
}
发表于 2023-11-18 17:12:10 回复(0)
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
#include <cstdio>
using namespace std;

int main(){
    int n,k,tmp;
    map<int,int> dict;
    cin>>n>>k;
    for(int i=0;i<n;i++){
        cin>>tmp;
        dict[tmp]++;
    }
    int ans=0;
    if(k==1){
        ans = dict.size();
        cout<<ans<<endl;
        return 0;
    }
    for(map<int,int>::iterator it=dict.begin();it!=dict.end();it++){
        if(it->second==0) continue;
        vector<int> v;
        vector<decltype(it)> its;
        for(auto kit = it;kit!=dict.end();kit = dict.find(kit->first*k)){ // log_k(max(a))
            v.push_back(kit->second);
            its.push_back(kit);
            kit->second = 0;
            // printf("v: %d, count: %d\n",kit->first, kit->second);
        }
        if(v.size()==1){
            ans += v[0];
            continue;
        }
        if(v.size()==2){
            ans += max(v[0],v[1]);
            continue;
        }
        // 问题转化成了: 在数组v中, 找出子序列的最大和, 要求子序列满足选取的数组元素之间要么隔了1个数要么隔了2个数
        vector<int> f(v.size()); // 递推方程: f[i] = v[i] + max(f[i-2], f[i-3])
        f[0] = v[0];
        f[1] = v[1];
        f[2] = v[0]+v[2];
        for(int i=3;i<v.size();i++){
            f[i] = v[i] + max(f[i-2], f[i-3]);
        }
        ans += max(f[v.size()-1], f[v.size()-2]);
    }
    cout<<ans<<endl;
    return 0;
}

发表于 2019-09-27 15:06:28 回复(0)
import java.util.*;
public class Main{

    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        Long n = (long) sc.nextInt();
        Long k = (long) sc.nextInt();
        Map<Long, Integer> map = new TreeMap<>();
        for(int i = 0; i < n; i++){
            Long x = (long) sc.nextInt();

            if(!map.containsKey(x)){
                map.put(x, 1);
            }else{
                map.put(x, map.get(x)+1);
           }
        }
        if(k == 1){
            System.out.println(map.size());
            return;
        }
        int count = 0;
        for(Long key : map.keySet()){ //抵消掉成倍数关系的数
            while(map.get(key)>=1 && map.containsKey(key*k) && map.get(key*k) >= 1){
                count++;
                map.put(key, map.get(key)-1);
                map.put(key*k, map.get(key*k)-1);
            }
        }
        System.out.println(n-count);
        
    }
}

发表于 2019-08-22 14:18:00 回复(1)
//#include <bits/stdc++.h>
#include<iostream>
#include<map>

using namespace std;
int main()
{
    int n,k,input;
    cin>>n>>k;
    map<int,int> m;
    for (int i=0;i<n;i++)
    {
        cin>>input;
        m[input]++;
    }
    if (k == 1)
    {
        cout<<m.size();
        return 0;
    }
    int cnt = 0;
    for (auto it = m.begin();it != m.end();it++)
    {    /*
        while (m[it->first]>=1 && m[(it->first)*k]>=1)
        {
            cnt++;
            m[(it->first)*k]--;
            m[it->first]--;
        }
        */
        if(m[it->first] && m[(it->first)*k]){ //本渣渣改进的别人的算法
            if(m[it->first] >= m[(it->first)*k]){
                m[it->first] -= m[(it->first)*k];
                cnt += m[(it->first)*k];
                m[(it->first)*k] = 0;
            }
            else{
                m[(it->first)*k] -= m[it->first];
                cnt += m[it->first];
                m[it->first] = 0;
            }
        }
    }
    cout << n - cnt;
    return 0;
}
发表于 2019-07-13 21:57:28 回复(0)