均分纸牌 及 环形均分纸牌
均分纸牌
题目描述
有N堆纸牌,编号分别为 1,2,…,N每堆上有若干张,但纸牌总数必为N的倍数。可以在任一堆上取若干张纸牌,然后移动。
移牌规则为:在编号为1堆上取的纸牌,只能移到编号为2的堆上;在编号为N的堆上取的纸牌,只能移到编号为N−1的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上,每次只能移一张牌
现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多
思路
(前言纸牌总数必为n的倍数保证一定有解
不难想到最终每堆牌上的数即为平均数
具体操作及每一堆减去平均数后,从第一堆开始枚举,如果数大于零说明多于平均数要给其他堆,反之需要从别个堆哪里拿过来
sum[i]为前i堆的前缀和,aver为平均数
类似题目NOIP2002 提高组均分纸牌(一次移多次题目
题目描述
简明题意:
行列分别为环形的均分纸牌
思路
首先要考虑满足是否有解,同上,只有各行摊点总数为行数的倍数,一定有解,同理,列数亦然
再考虑求解
假设 为给的牌数,如果为负数,则为给的牌数,再设为给的牌数,这样就构成了环
(这里有点像向量,数学好的同学可以从向量的角度理解
则答案
接着因为均分后的纸牌都为aver,则可以推出下列式子
简单解释下这个式子,第一堆变为aver,加上给它的纸牌,减去给出去的纸牌
同理
........
因为答案的和式与有关
尝试用其他形式将表达出来
根据上述已有关系
可以推出
........
令
设m[1]=0;
则
(注意这里是可以求出来的,aver和a[i]都是已知的
接下来关键就是怎么求
其实通过观察这和式
可以举个例子 |a-3|+|a+3|为最小值时 a的值为?
运用初中数轴的知识 易得-3<=a<=3
推广一下,设序列
其实此时是这个式子最小的数为b_{i}的中位数
- 来看一下中位数的定义就知道为什么
中位数(Median)又称中值,统计学中的专有名词,是按顺序排列的一组数据中居于中间位置的数,代表一个样本、种群或概率分布中的一个数值,其可将数值集合划分为相等的上下两部分。对于有限的数集,可以通过把所有观察值高低排序后找出正中间的一个作为中位数。如果观察值有偶数个,通常取最中间的两个数值的平均数作为中位数 ---来自百度百科(侵删
所以再看这个
将求出来,排序令
设M序列长度为n
当为n偶数,则
当为n奇数,则
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 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步