codeforces 910c
转自两位大佬:http://www.cnblogs.com/wkfvawl/p/9387634.html
https://i.cnblogs.com/EditPosts.aspx?opt=1
You are given an array a consisting of n integers a1, ..., an. In one operation, you can choose 2 elements ai and aj in which ai is divisible by aj and transform ai to aj.
A number x is said to be divisible by a number y if x can be divided by y and the result is an exact whole number. For example, 15 is divisible by 3, because 15÷ 3 = 5 exactly, but 9 is not divisible by 2 because 9÷ 2 is 4 with 1 left over.
Your task is to find the minimum sum of the array a that can be obtained by making as many transform operations as you want. Can you?
The first line contains an integer T (1 ≤ T ≤ 100) specifying the number of test cases.
The first line of each test case contains an integer n (1 ≤ n ≤ 105), in which n is the size of array a. Then a line follows containing n integers a1, ..., an (1 ≤ ai ≤ 106), giving array a.
The sum of n overall test cases does not exceed 3 × 106.
For each test case, print a single line containing the minimum sum of the array a that can be obtained after making as many transform operations as you want.
1
5
2 2 3 6 6
11
题目意思:有一个长度为n的数组,对于数组中的两个元素x,y如果满足y%x==0,则可以将y转换成x,求经过多次变换后数组的前n项和最小是多少。
由于数据量较大我们选择了map这一容器来去重。对容器中的每一个元素遍历,开始我的打算是将每一个元素的因子都拆分,再按照从小到大的顺序来一一枚举因子(因为如果容器中有元素等于交小的因子
替换后得到的答案就是最小的),可惜超时了,于是寻求另一种方法来解决。我同学给我提供了一个新的思路,我们在求某一个数的因子的时候,为了优化算法,降低时间复杂度,会采用一种方法,比如求
12的因子的时候,我们从1到12逐个遍历,知道2是12的因子,那么也能得到12/2=6也是12的因子;知道了3是12的因子,那么也同时得到了4也是12的因子。这里也是一样的,我们也是先依次去从小的因子
出发,找小的因子的过程中也找到了其对应的比其大的因子。如果小因子不存在,再看看对应的较大的那个因子是否存在,存在的话就保存下来。之后也是这样增大因子,重复这个过程,要是存在对应的交大的因子就更新保存的结果,这些较小的因子都找过了依旧不满足条件,那么就找那个保存的那个较大的因子。
还需要注意的是mp.erase(),当在迭代器中调用这个函数的话,需要先返回上一个迭代器,不然指针会变为一个野指针(可参考链表理解)。
#include<cstdio> #include<cstring> #include<algorithm> #include<map> #define LL long long int using namespace std; int main() { int t,flag,flag1; LL i,j,a,n,k; LL ans,x; map<LL,LL>mp; map<LL,LL>::iterator it; scanf("%d",&t); while(t--) { mp.clear(); scanf("%lld",&n); for(i=0;i<n;i++) { scanf("%lld",&a); mp[a]++; } flag=0; ans=0; for(it=mp.begin();it!=mp.end();it++) { k=it->first; if(k==1)///出现1 { flag=1; break; } flag1=0; x=0; for(i=2;i*i<=k;i++) { if(k%i==0) { if(mp.count(i))//查看i有没有 存在返回1,不存在返回0; { mp[i]+=mp[k]; it--; mp.erase(k); flag1=1; break; } else if(mp.count(k/i)) { x=k/i; } } } if(!flag1) { if(x) { mp[x]+=mp[k]; it--; mp.erase(k);//清空这一列 } } } if(flag) { printf("%lld ",n); } else { for(it=mp.begin();it!=mp.end();it++) { ans+=it->second*it->first; } printf("%lld ",ans); } } return 0; }