hdu6237-2017哈尔滨CCPC-质因子&贪心&暴力-A Simple Stone Game

来源:互联网 发布:传淘宝和关联宝贝 编辑:程序博客网 时间:2024/06/17 11:55

http://acm.hdu.edu.cn/showproblem.php?pid=6237
当我们枚举素因子的时候,
我们统计mod的和。sumb
并且对mod的结果搞一个b数组。
然后队友的思路是直接分为两半,然后左边那一半小的往右边那一半靠。
以下疑问:
①可能转移的时候中介线并不是一半。。
因为我们怎么确定b数组在范围内是线性的分布?
但是当时写的也有问题。没有考虑到贪心,
然后 最优的方案是让最大的变成pi(那个素因子)。那种花费最小。
可以直接倒着算,计算以下各个mod的和,后面的大数(升序)每搞一个,sumb就减去 因子,ans加上 因子和大数之差。
这里写图片描述
就是让小的填充到绿色部分。(红线是mod)。 这样花费最低(如果让大的取填小的,看着就多。)
有一个简短的数学证明(思维)。这样处理是肯定可以得到结果的。
因为sumb 是pi的倍数,所以b数组中的每一个数mod pi,和也一定是倍数。因此这种处理方法是有效的,对所有情况都适用的。
有一个优化,直接从大到小,sumb-=pi。ans+=vec[i]-p[j]。这样少一个循环。并且很多代码都是这样qwq
g++比c++快。
但是g++得用i64d。。。。。!!!

  #include <iostream>#include <cstring>#include <cstdio>#include <vector>#include <algorithm>using namespace std;/* 为什么我这么菜。   cf上做过一道类似的。和这一道题意思差不多。   都有贪心的一些意思。我怎么就没想到。   不过那个是修改(本质也是让其花费尽可能的小)   当我们枚举素因子的时候,   我们统计mod的和。sumb   并且对mod的结果搞一个b数组。   然后队友的思路是直接分为两半,然后左边那一半小的往右边那一半靠。   以下疑问:   ①可能转移的时候中介线并不是一半。。   因为我们怎么确定b数组在范围内是线性的分布?   但是当时写的也有问题。没有考虑到贪心,   然后 最优的方案是让最大的变成pi(那个素因子)*/typedef long long ll;ll sum;const int maxn=1e5+200;ll a[maxn];vector<ll>vec;vector<ll>q;int main(){   int t,m;     scanf("%d",&t);     while(t--){           sum=0;           scanf("%d",&m);           for(int i=0;i<m;i++){               scanf("%I64d",&a[i]);               sum+=a[i];           }         vec.clear();         q.clear();         //素因子这个也没有想到。。          for(ll i=2;i*i<=sum;i++)           //求出总和的质因子        {            if(sum%i==0)            {                vec.push_back(i);                while(sum%i==0)                {                    sum/=i;                }            }        }        if(sum>1)            vec.push_back(sum);        ll res=1e17;        for(int i=0;i<vec.size();i++){            q.clear();            ll ans=0;             sum=0;            for(int j=0;j<m;j++){                 ll b=a[j]%vec[i];                 q.push_back(b);                 sum+=b;            }            int siz=sum/vec[i];            int  siz2=0;            ll sum2=0;            sort(q.begin(),q.end());            for(int j=q.size()-1;j>=0;j--){                sum2+=(vec[i]-q[j]);                siz2++;                if(siz2==siz) break;            }            for(int j=0;j<q.size();j++){                ans+=q[j];                sum2-=q[j];                if(sum2<=0) break;            }            res=min(res,ans);        }        printf("%I64d\n",res);//i64d。!!!     }    return 0;}
原创粉丝点击