为了能到远方,脚下的每一步都不能少.|

园龄:粉丝:关注:

均分纸牌 及 环形均分纸牌

均分纸牌

题目描述
有N堆纸牌,编号分别为 1,2,…,N每堆上有若干张,但纸牌总数必为N的倍数。可以在任一堆上取若干张纸牌,然后移动。
移牌规则为:在编号为1堆上取的纸牌,只能移到编号为2的堆上;在编号为N的堆上取的纸牌,只能移到编号为N−1的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上,每次只能移一张牌
现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多

思路
(前言纸牌总数必为n的倍数保证一定有解
不难想到最终每堆牌上的数即为平均数 ​i=1na[i]n
​具体操作及每一堆减去平均数后,从第一堆开始枚举,如果数大于零说明多于平均数要给其他堆,反之需要从别个堆哪里拿过来
ans=i=1nsum[i]iaver
sum[i]为前i堆的前缀和,aver为平均数

类似题目NOIP2002 提高组均分纸牌(一次移多次题目

七夕祭

题目描述
简明题意:
行列分别为环形的均分纸牌

思路

首先要考虑满足是否有解,同上,只有各行摊点总数为行数的倍数,一定有解,同理,列数亦然
再考虑求解
假设SiSiSi+1的牌数,如果Si为负数,则为Si+1Si的牌数,再设Sn为给S1的牌数,这样就构成了环
(这里有点像向量,数学好的同学可以从向量的角度理解

则答案 ans=i=1n|S1|

接着因为均分后的纸牌都为aver,则可以推出下列式子
a[1]+SnS1=aver
简单解释下这个式子,第一堆变为aver,加上Sn给它的纸牌,减去S1给出去的纸牌
同理
a[2]+S1S2=aver
a[3]+S2S3=aver
........
a[n]+Sn1Sn=aver
因为答案的和式与Si有关
尝试用其他形式将Si表达出来

根据上述已有关系
可以推出
S2=a[2]+S1aver
S3=a[3]+S2aver=S1(2aver(a[2]+a[3]))
S4=a[4]+S3aver=S1(3aver(a[2]+a[3]+a[4]))
........
Sn=a[n]+Sn1aver=S1i=2n(avera[i])

Mi=j=2i(avera[j])(2<=i<=n)
Si=S1Mi
ans=i=1n|S1|=i=2n(|S1Mi|)+S1
设m[1]=0;
ans=i=1n|S1|=i=1n(|S1Mi|)
(注意这里Mi是可以求出来的,aver和a[i]都是已知的

接下来关键就是怎么求S1
其实通过观察这和式
可以举个例子 |a-3|+|a+3|为最小值时 a的值为?
运用初中数轴的知识 易得-3<=a<=3
推广一下,设序列bi
|ab1|+|ab2|+.....+|abk|+.....|abn|
其实此时是这个式子最小的数为b_{i}的中位数

  • 来看一下中位数的定义就知道为什么
    中位数(Median)又称中值,统计学中的专有名词,是按顺序排列的一组数据中居于中间位置的数,代表一个样本、种群或概率分布中的一个数值,其可将数值集合划分为相等的上下两部分。对于有限的数集,可以通过把所有观察值高低排序后找出正中间的一个作为中位数。如果观察值有偶数个,通常取最中间的两个数值的平均数作为中位数 ---来自百度百科(侵删

所以再看这个i=1n|S1Mi|
Mi求出来,排序令Si=M
设M序列长度为n
当为n偶数,则Si[Sn2,Sn2+1]
当为n奇数,则Si=Sn2+1

code

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

int n,m,t;
const int maxx=1e5+10;
int r[maxx],c[maxx];
long long cz(int *a,int len){
    int aver=t/len;
    long long sum=0;long long m[maxx];m[1]=0;
    for(int i=2;i<=len;++i){
        sum+=a[i];
        m[i]=(i-1)*aver-sum;
    }sort(m+1,m+1+len);
    int mid=m[len/2+1];long long ans=0;
    for(int i=1;i<=len;++i) 
        ans+=abs(mid-m[i]);
    return ans;
}
int main(){
    scanf("%d%d%d",&n,&m,&t);
    for(int i=1;i<=t;++i){
        int x,y;
        scanf("%d%d",&x,&y);
        r[x]++,c[y]++;
    }
    if(t%n && t%m){
        printf("impossible");
        return 0;
    }if(t%n==0 && t%m==0 ){
        printf("both %lld",(long long)(cz(r,n)+cz(c,m)));
        return 0;
    }
    else if(t%n==0){
        printf("row %lld",cz(r,n));
        return 0;
    }else printf("column %lld",cz(c,m));
}

ZFY AK IOI

本文作者:归游

本文链接:https://www.cnblogs.com/guiyou/p/15100774.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   归游  阅读(306)  评论(1编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起