Codeforces gym101612 E.Equal Numbers(贪心)

传送:http://codeforces.com/gym/101612

题意:给出一个大小为n的序列a[i],每次选其中一个数乘以一个正整数,问进行k步操作后最少剩下多少种数字,输出0kn,所有的k的答案。

注意这k步不一定是连续的。

分析:

对于每个数,可以有两种操作:

1. 先将有倍数的数变成它们的最大倍数,而且按照出现次数比较少的先变。

2. 将所有数都变成lcm,而且按照出现次数比较少的先变。

数组f[i]代表,操作i次的最小种类数。对于每一次操作,取min。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=3e5+10;
 4 const int inf=1e6+10;
 5 map<int,int> mp; 
 6 vector<int> v[2];
 7 int f[maxn];
 8 int main(){
 9     freopen("equal.in","r",stdin);
10     freopen("equal.out","w",stdout);
11     int n,xx; cin >> n;
12     mp.clear();
13     for (int i=0;i<n;i++){
14         cin >> xx;
15         mp[xx]++;
16     }    
17     int num=mp.size();
18     v[0].clear(); v[1].clear(); 
19     for (auto it:mp){
20         int i=it.first;
21         v[0].push_back(it.second);
22         for (int j=i+i;j<inf;j+=i)
23             if (mp.count(j)){
24                 v[1].push_back(it.second); break;
25             }
26     }
27     memset(f,0x7f,sizeof(f));
28     f[0]=num;
29     //变成该数的倍数(在数列中出现)
30     sort(v[1].begin(),v[1].end());
31     int len=v[1].size(),sum=0;
32     for (int i=0;i<len;i++){
33         sum+=v[1][i];
34         f[sum]=min(f[sum],num-(i+1));
35     }
36     //变成最小公倍数
37     sort(v[0].begin(),v[0].end());
38     len=v[0].size(); sum=0;
39     for (int i=0;i<len;i++){
40         sum+=v[0][i];
41         f[sum]=min(f[sum],num-i);
42     } 
43     cout << f[0];
44     for (int i=1;i<=n;i++){
45         if (i) f[i]=min(f[i],f[i-1]);
46         cout << " " << f[i];
47     }
48     cout << endl;
49     return 0;
50 } 

 

原文地址:https://www.cnblogs.com/changer-qyz/p/9967993.html