牛客 七夕祭
https://ac.nowcoder.com/acm/contest/1001/C
题面
Vani预先联系了七夕祭的负责人zhq,希望能够通过恰当地布置会场,使得各行中cl感兴趣的摊点数一样多,并且各列中cl感兴趣的摊点数也一样多。
不过zhq告诉Vani,摊点已经随意布置完毕了,如果想满足cl的要求,唯一的调整方式就是交换两个相邻的摊点。两个摊点相邻,当且仅当他们处在同一行或者同一列的相邻位置上。由于zhq率领的TYVJ开发小组成功地扭曲了空间,每一行或每一列的第一个位置和最后一个位置也算作相邻。现在Vani想知道他的两个要求最多能满足多少个。在此前提下,至少需要交换多少次摊点。
1≤N,M≤1000001,0≤T≤min(N×M,100000),1≤x≤N,1≤y≤M。
分析
考虑行和列互不影响,可以分开做,这变成了首尾相接的均分纸牌问题
考虑普通的均分纸牌,牌数为\(a_1,a_2,……,a_n\)
分完后所有卡牌一样,所以可以事先减去\(\frac{\sum_{i=1}^{n}a_i}{n}\),记作\(b_i\)
对\(b_i\)做前缀和,记作\(S_i\),\(S_n=0\),分完后\(b_i=0,S_i=0\)
通过找规律可以发现,将1张纸牌移到相邻位置只会有一个\(S_i\)变化1
所以所需要移动的最少次数为\(\sum_{i=1}^{n}|S_i|\)
如果首尾相接,显然有一对相邻的不用相互交换
枚举断点为K,则前缀和变为\(S_K-S_{K-1},S_{K+1}-S_{K-1},……,S_n-S_{K-1},S_1+S_n-S_{K-1},S_2+S_n-S_{K-1},……,S_{K-1}+S_n-S_{K-1}\)
又因为\(S_n\)=0,所以最少移动次数为\(\sum_{i=1}^{n}|S_i-S_K|\)
对S排序后取中间那个为K即可
时间复杂度\(O(nlgn)\)
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,m,t,a[N],b[N],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);
a[x]++,b[y]++;
}
if(t%n==0) {
for(int i=1;i<=n;i++) {
a[i]=a[i-1]+a[i]-t/n;
}
sort(a+1,a+n+1);
for(int i=1;i<=n;i++) {
ans+=abs(a[i]-a[(1+n)>>1]);
}
}
if(t%m==0) {
for(int i=1;i<=m;i++) {
b[i]=b[i-1]+b[i]-t/m;
}
sort(b+1,b+m+1);
for(int i=1;i<=m;i++) {
ans+=abs(b[i]-b[(1+n)>>1]);
}
}
if(t%n==0&&t%m==0) printf("both %d\n",ans);
else if(t%n==0) printf("row %d\n",ans);
else if(t%m==0) printf("column %d\n",ans);
else puts("impossible");
return 0;
}

浙公网安备 33010602011771号