智商恢复训练(中位数)

在一个有序序列里,中位数有一些很优美的性质。

1
货仓选址
在一条数轴上有 N N N家商店,它们的坐标分别为 A 1 … A N A_1…A_N A1AN
现在需要在数轴上建立一家货仓,每天清晨,从货仓到每家商店都要运送一车商品。为了提高效率,求把货仓建在何处,可以使得货仓到每家商店的距离之和最小。

我们设在仓库左边的点有p个,右边的有q个,若p < q,当仓库向右移动的话,距离之和会减少,如p>q ,当仓库向左移动的话,距离之和会减少,所以说当p = q时为最优解。因此货仓建在中位数处。

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)

typedef long long ll;

const int maxn = 100000+1000;

int n;
int a[maxn];
int main(int argc, char const *argv[])
{
	scanf("%d",&n);
	rep(i,0,n)
	{
		scanf("%d",&a[i]);
	}
	sort(a,a+n);
	int mid = a[(n+1)/2];
	ll ans = 0;
	rep(i,0,n)
	{
		ans += abs(a[i] - mid);
	}
	printf("%lld\n",ans);
	return 0;
}

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

假如每次只能移动一个
a n s = ∑ i = 1 N ∣ S [ i ] ∣ ans = \sum_{i = 1}^{N}|S[i]| ans=i=1NS[i] 其中S是A的前缀和 s [ i ] = ∑ j = 1 i A [ j ] s[i] = \sum_{j=1}^{i}A[j] s[i]=j=1iA[j]
A [ i ] = c [ i ] − T / N A[i] = c[i]-T/N A[i]=c[i]T/N
对于这题,只需要判断 S [ i ] S[i] S[i]不等于0的情况加一

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
typedef long long ll;

const int maxn = 1e3;

int n;
int a[maxn];
int f[maxn];
int main(int argc, char const *argv[])
{
	scanf("%d",&n);
	ll sum = 0;
	ll ans = 0;
	rep(i,1,n+1)
	{
		scanf("%d",&a[i]);
		sum += a[i];
	}
	sum /= n;
	// printf("%lld\n",sum);
	rep(i,1,n+1)
	{
		a[i] -= sum;
		f[i] = f[i-1] + a[i];
		if(!f[i]) continue;
		ans++;
	}
	// rep(i,1,n+1)
	// {
	// 	ans += abs(f[i]);
	// }
	printf("%lld\n",ans );
	return 0;
}

BZOJ 1045 环形均分纸牌
想普通的均分纸牌,断一下就能得到答案
a n s = ∑ i = 1 N ∣ S [ i ] − S [ k ] ∣ ans = \sum_{i = 1}^{N}|S[i]-S[k]| ans=i=1NS[i]S[k]
需要枚举K吗?想一想第一个题, S [ k ] S[k] S[k]为中位数时最优
注意此题的数据范围

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
typedef long long ll;

const int maxn = 1000005+100;

int n;
int a[maxn];
int main(int argc, char const *argv[])
{
	scanf("%d",&n);
	ll sum = 0;
	rep(i,1,n+1)
	{
		scanf("%d",&a[i]);
		sum += a[i];
	}
	sum /= n;

	rep(i,1,n+1)
	{
		a[i] -= sum;
		a[i] += a[i-1];
	}
	sort(a+1,a+n+1);
	ll mid = a[(n+1)/2];
	ll ans = 0;
	rep(i,1,n+1)
	{
		ans += abs(a[i]-mid);
	}
	printf("%lld\n",ans);
	return 0;
}

[BZOJ3032]七夕祭(中位数)
分割成行和列两个独立的子问题

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
typedef long long ll;

const int maxn=100010;

int x[maxn],y[maxn],s1[maxn],s2[maxn];

int n,m,T;
int a,b;
int main(int argc, char const *argv[])
{
    scanf("%d%d%d",&n,&m,&T);

    rep(i,1,T+1)
    {
        scanf("%d%d",&a,&b);
        x[a]++,y[b]++;
    }
    if(T%m!=0 && T%n!=0)
    {
        printf("impossible\n");
        return 0;
    }
    rep(i,1,n+1) x[i]-=T/n;
    rep(i,1,m+1) y[i]-=T/m;
    ll ans=0;
    if(T%n==0)
    {
        rep(i,1,n+1) 
        s1[i]=s1[i-1]+x[i];
        sort(s1+1,s1+n+1);
        ll mid=s1[(n+1)/2];
        rep(i,1,n+1)
            ans+=abs(s1[i]-mid);
    }
    if(T%m==0)
    {
        rep(i,1,m+1)
        s2[i]=s2[i-1]+y[i];
        sort(s2+1,s2+m+1);
        ll mid=s2[(m+1)/2];
        rep(i,1,m+1)
            ans+=abs(s2[i]-mid);
    }
    if(T%n==0 && T%m==0) 
        printf("both ");
    else if(T%n==0 && T%m!=0) 
        printf("row ");
    else 
        printf("column ");
    printf("%lld\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值