zoukankan      html  css  js  c++  java
  • [bzoj3032][TYVJ P1924]七夕祭(环形均分纸牌,货仓选址)

    题意

    七夕节因牛郎织女的传说而被扣上了「情人节」的帽子。
    于是TYVJ今年举办了一次线下七夕祭。
    Vani同学今年成功邀请到了cl同学陪他来共度七夕,于是他们决定去TYVJ七夕祭游玩。
    TYVJ七夕祭和11区的夏祭的形式很像。
    矩形的祭典会场由N排M列共计N×M个摊点组成。
    虽然摊点种类繁多,不过cl只对其中的一部分摊点感兴趣,比如章鱼烧、苹果糖、棉花糖、射的屋……什么的。
    Vani预先联系了七夕祭的负责人zhq,希望能够通过恰当地布置会场,使得各行中cl感兴趣的摊点数一样多,并且各列中cl感兴趣的摊点数也一样多。
    不过zhq告诉Vani,摊点已经随意布置完毕了,如果想满足cl的要求,唯一的调整方式就是交换两个相邻的摊点。
    两个摊点相邻,当且仅当他们处在同一行或者同一列的相邻位置上。
    由于zhq率领的TYVJ开发小组成功地扭曲了空间,每一行或每一列的第一个位置和最后一个位置也算作相邻。
    现在Vani想知道他的两个要求最多能满足多少个。
    在此前提下,至少需要交换多少次摊点。

    输入格式

    第一行包含三个整数N和M和T,T表示cl对多少个摊点感兴趣。
    接下来T行,每行两个整数x, y,表示cl对处在第x行第y列的摊点感兴趣。

    输出格式

    首先输出一个字符串。
    如果能满足Vani的全部两个要求,输出both;
    如果通过调整只能使得各行中cl感兴趣的摊点数一样多,输出row;
    如果只能使各列中cl感兴趣的摊点数一样多,输出column;
    如果均不能满足,输出impossible。
    如果输出的字符串不是impossible, 接下来输出最小交换次数,与字符串之间用一个空格隔开。

    数据范围

    (1≤N,M≤100000,)
    (0≤T≤min(N∗M,100000),)
    (1≤x≤N,)
    (1≤y≤M)

    首先可以发现,每一行进行交换不会影响到每一列的摊位,同理同一列进行交换也不会影响到每一行的摊位。所以我们可以分开解决行和列。我们拿行来举例。
    我们要通过交换邻项,使每一行的摊位数都相同,这个摊位数等于(T/n),这就是一个环形的均分纸牌问题。
    我们先考虑普通的均分纸牌。
    设a[i]为i行的摊位数,我们把每一个a[i]减去(T/n),设s为a的前缀和。
    那么答案为$$sum_{i = 1}^n{|s[i]|}$$
    对于环形的均分纸牌,我们可以枚举断点,把环断开,这样问题就重新成为了普通的均分纸牌。
    假如断点为k,那么断开后的环大概长这样(->),(k+1,k+2... n,1 ,2, 3, 4 ... k - 1,k)
    这时候前缀和就变了样:
    (原来-------现在)
    (s[k+1]-----s[k+1]-s[k])
    (s[k+2]-----s[k+2]-s[k])
    (.......................)
    (s[n]-------s[n]-s[k])
    (s[1]-------s[n]-s[k]+s[1])
    (s[2]-------s[n]-s[k]+s[2])
    因为a减掉了(T/n),所以s[n] = 0
    那么所需的交换次数就是$$sum_{i = 1}^n{|s[i]-s[k]|}$$
    上式何时最小?
    这就是另一个经典问题货仓选址,当s[k]是s的中位数时,答案最小。

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    ll x[100010],y[100010];
    ll sum[100010];
    ll n,m,t;
    int main(){
    	cin >> n >> m >> t;
    	for(int i = 1; i <= t; ++i){
    		int xx,yy;
    		scanf("%d%d",&xx,&yy);
    		x[xx]++; y[yy]++;
    	}
    	ll ans1 = 0,ans2 = 0;
    	int flag1 = 1,flag2 = 1;
    	ll ave = 0;
    	if(t % n == 0){
    		ave = t / n;
    		for(int i = 1; i <= n; ++i)
    			sum[i] = sum[i - 1] + x[i] - ave;
    		sort(sum + 1,sum + n + 1);
    		ll mid = (n + 1) >> 1;
    		for(int i = 1; i <= n; ++i)
    			ans1 += abs(sum[i] - sum[mid]);
    	}
    	else flag1 = 0;
    	if(t % m == 0){
    		ave = t / m;
    		for(int i = 1; i <= m; ++i)
    			sum[i] = sum[i - 1] + y[i] - ave;
    		sort(sum + 1,sum + m + 1);
    		ll mid = (m + 1) >> 1;
    		for(int i = 1; i <= m; ++i)
    			ans2 += abs(sum[i] - sum[mid]);
    	}
    	else flag2 = 0;
    	if(flag1 && flag2) cout << "both ";
    	else if(flag1) cout << "row ";
    	else if(flag2) cout << "column ";
    	else cout << "impossible" << endl;
    	if(flag1 || flag2) cout << ans1 + ans2 << endl;
    	return 0;
    } 
    
  • 相关阅读:
    Java实现AES加密
    spring定时任务详解(@Scheduled注解)
    springBoot 项目war包部署及改为war包后资源路径错误问题
    (转)如何在maven的pom.xml中添加本地jar包
    HttpClient MultipartEntityBuilder 上传文件
    Java BigDecimal详解
    mysq带条件的分页查询数据结果错误
    jstack生成的Thread Dump日志线程 分析
    jquery将表单序列化
    java jdk动态代理学习记录
  • 原文地址:https://www.cnblogs.com/FoxC/p/11417492.html
Copyright © 2011-2022 走看看