均分纸牌 及 环形均分纸牌

均分纸牌

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

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

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

七夕祭

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

思路

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

则答案 \(ans=\sum_{i=1}^{n}|S_{1}|\)

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

根据上述已有关系
可以推出
\(S_{2}=a[2]+S_{1}-aver\)
\(S_{3}=a[3]+S_{2}-aver=S_{1}-(2*aver-(a[2]+a[3]))\)
\(S_{4}=a[4]+S_{3}-aver=S_{1}-(3*aver-(a[2]+a[3]+a[4]))\)
........
\(S_{n}=a[n]+S_{n-1}-aver=S_{1}-\sum_{i=2}^{n}(aver-a[i])\)

\(M_{i}=\sum^{i}_{j=2}(aver-a[j])(2<=i<=n)\)
\(S_{i}=S_{1}-M_{i}\)
\(ans=\sum_{i=1}^{n}|S_{1}|=\sum_{i=2}^{n}(|S_{1}-M_{i}|)+S_{1}\)
设m[1]=0;
\(ans=\sum_{i=1}^{n}|S_{1}|=\sum_{i=1}^{n}(|S_{1}-M_{i}|)\)
(注意这里\(M_{i}\)是可以求出来的,aver和a[i]都是已知的

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

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

所以再看这个\(\sum_{i=1}^{n}|S_{1}-M_{i}|\)
\(M_{i}\)求出来,排序令\(S_{i}=M序列的中位数\)
设M序列长度为n
当为n偶数,则\(S_{i}∈[S_{\frac{n}{2}}, S_{\frac{n}{2}+1}]\)
当为n奇数,则\(S_{i}=S_{\frac{n}{2}+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

posted @ 2021-08-04 21:03  归游  阅读(276)  评论(1编辑  收藏  举报