zoukankan      html  css  js  c++  java
  • 我又来博客划水啦

    本文使用Typora编辑,这或许是windows平台上最好用的本地markdown编辑器了

    我又来博客划水啦

    啊我起标题都好随意啊

    今天讲的内容很水,就是贪心。

    可能很多人会觉得贪心都是错的,其实有些简单的问题,贪心就是正解了!(动态规划好烦

    今天的混更分量非常大!

    先引入一题真题。

    NOIp2002均分纸牌

    这题的思路就是贪。一堆纸牌,总能也仅能分给两边的纸牌堆或从两边的纸牌堆得到纸牌。

    记总n堆中第i堆纸牌数量为a[i],总和为sum

    计算出均分后每堆纸牌数量sum/n

    a[i]=a[i]-sum/n,就是每堆的操作纸牌数。

    • >0,则是多了,需要移到右边(为了方便,都从左边移到右边),a[i+1]+=a[i]
    • =0,则正好足够,不需要移动
    • <0,则不够,需要从右边移过来。a[i+1]+=a[i](a[i]已经是负数了)

    实现起来的话,就是这样的:

    #include<iostream>
    #include<cstdio>
    using namespace std;
    inline void in(int &p,char c=getchar())
    {
        while(c<'0' or c>'9')
            c=getchar();
        p=0;
        while(c>='0' and c<='9')
            p=p*10+c-'0',c=getchar();
    }
    int a[101],aver,ans;
    int main()
    {
        int n;
        in(n);
        for(int i=0;i<n;i++)
        {
            in(a[i]);
            aver+=a[i];
        }
        aver/=n;
        for(int i=0;i<n-1;i++)
        {
            a[i]-=aver;
            if(a[i])
                a[i+1]+=a[i],ans++;
        }
        cout<<ans;
        return 0;
    }
    

    好,下面升级一下。

    均分纸牌plus

    第1堆和第n堆之间也可以给牌了。

    也就是,原来链状的纸牌堆,变成了环状。

    这个时候如果还用上面的方法不改动的话就会算多次数(所以说可以枚举起点,算n次再取min)

    对于环状,正解是找一个最优的..额

    设 bi 的前缀和为 si。如果从第 k 个位置开始,那么第 i 堆和第 i+1 堆交换的纸牌数就是 |si-sk|。总代价就是|s1-sk|+|s2-sk|+|s3-sk|+……+|sn-sk|。发现什么了?当 sk 是 s1~sn 中位数的时候,上式有最小值!所以把 si 排序后,令 sk=s[(n+1)/2],计算代价即可。

    时间复杂度 O(nlogn),预计得分 100 分。

    实现起来的话,是这样的

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    inline int in(int &p,char c=getchar())
    {
    	while(c<'0' or c>'9')
    		c=getchar();
    	p=0;
    	while(c>='0' and c<='9')
    		p=p*10+c-'0',c=getchar();
    	return p;
    }
    inline long long inl(long long &p,char c=getchar())
    {
    	while(c<'0' or c>'9')
    		c=getchar();
    	p=0;
    	while(c>='0' and c<='9')
    		p=p*10+c-'0',c=getchar();
    	return p;
    }
    long long hang[1000000+1],f[1000000+1];
    int n,m,t,x;
    long long calc_hang()
    {
    	long long ans=0;
    	hang[0]/=n;
    	for(int i=1;i<=n;i++)
    	{
    		hang[i]-=hang[0];
    		f[i]=f[i-1]+hang[i];
    	}
    	sort(f+1,f+n+1);
    	for(int i=1;i<=n;i++)
    		ans+=abs(f[i]-f[(1+n)>>1]);
    	return ans;
    }
    int main()
    {
    	in(n);
    	for(int i=1;i<=n;i++)
    		hang[0]+=inl(hang[i]);
    	printf("%lld",calc_hang());
    	return 0;
    }
    

    好像也很好懂(似懂非懂.jpg)呢!

    最后再来个变式

    均分纸牌X

    如果您打不开这个题目,说明您和这题没有缘分,请点右上角关闭

    这题又有行,又有列的,吓死人了。

    其实只是多了一大堆纸牌。

    先计算以行为单位,各行的摊位数,sum摊位数

    再计算以列为单位,各列的摊位数,sum摊位数

    如果连%行数 or %列数都不==0,说明无论怎么分,都分不均匀的。

    再以行为单位考虑移动摊位,以列为单位考虑移动摊位。

    最后简单相加即得答案。

    	if(hang[0]%n==0 and lie[0]%m==0)
            printf("both %lld",calc_hang()+calc_lie());
        else if(hang[0]%n==0)
            printf("row %lld",calc_hang());
        else if(lie[0]%m==0)
            printf("column %lld",calc_lie());
        else
            printf("impossible");
    

    我这里为了节约空间,把sum存在0了。

    最后的最后,%一下轻松ac的だらお们

    だらお

  • 相关阅读:
    Apache服务器的简单配置与安全策略
    Linux下的ICMP反弹后门:PRISM
    项目年度任务失败总结
    SpringBoot下配置Druid
    ftm国际化解决方案
    SpringBoot自动装配源码解析
    log4j到log4j2升级迁移方案
    Linux常用命令记录
    MySQL安装后无法用root用户访问的问题
    html实体命名
  • 原文地址:https://www.cnblogs.com/syhien/p/7753038.html
Copyright © 2011-2022 走看看