刺激的矩阵exciting

8 篇文章 0 订阅
刺激的矩阵(exciting)


【输入格式】
从文件 exciting.in 中读入数据。
第一行 3 个整数 n,m,type,分别表示矩阵的行数、列数和数据类型。(数据类型的作用会在下面描述)
接下来 n 行,每行 m 个用空格隔开的整数,描述这个矩阵。其中第 i + 1 行的第 j个数表示 A i,j 。
【输出格式】
输出到文件 exciting.out 中。
输出一行一个整数,表示需要修改的最少的数的个数。

【样例 1 输入】
3 3 2
10 20 30
20 10 30
10 5 35
【样例 1 输出】
1
【样例 2 输入】
3 3 1
1 2 1
2 1 0
3 3 4
【样例 2 输出】
0
【样例 3 输入】
4 4 0
1 1 3 4
5 1 1 8
9 10 1 1
1 14 15 1
【样例 3 输出】
2
【样例 4】
见选手目录下的 exciting/exciting4.in 与 exciting/exciting4.ans。
【样例 5】
见选手目录下的 exciting/exciting5.in 与 exciting/exciting5.ans。

【子任务】
对于 8% 的数据,保证 n,m ≤ 3,且 type = 1。
对于另外 8% 的数据,有 type = 2。
对于另外 4% 的数据,有 n,m ≤ 5。
对于另外 12% 的数据,保证 n ≤ 10。
对于 44% 的数据,保证 n,m ≤ 35。
对于 56% 的数据,保证 n,m ≤ 60。
对于 64% 的数据,保证 n,m ≤ 100。
对于 72% 的数据,保证 n,m ≤ 300。
对于 88% 的数据,保证 n,m ≤ 1,000。
对于 92% 的数据,保证 n,m ≤ 1,500。
对于 100% 的数据,保证 1 ≤ n,m ≤ 2,000,0 ≤ A i,j ≤ 3 × 10 6 。
对于没有说明 type 取值的数据类型,都有 type = 0。
对于 type = 1 的数据,保证存在一种最优的修改方案,使得最终得到的刺激矩阵的
每个元素都是不超过 5 的非负整数。
对于 type = 2 的数据,保证答案不超过 1。



这道题乍一看没什么思路确实,除了暴力好像没什么突破口。可乱搞乱搞20分是很好拿的。

本蒟蒻啊比较草率想到中途就不往下想了,做了n^4的64分。

那就从最简单的64分说起。可以这样想。如果(i,j)上的值是作为R的,那么它一定也作为C。

所以我们就枚举这个中心,然后枚举将这个中心改为哪个数,这个数当然应该要在原来的矩阵中出现的。然后将它所在的行上比这个数小的数全部修改,把它所在列上比它大的全部修改。这样的时间复杂度是O(n^5)的,再想一想,这个点上的值能修改成什么呢,其实只要修改成它所在的行或列上的点的值。那么就可以变到O(n^4)。


这道题现场考试竟然有人AC,fkc大佬,用O(n^2logn)的方法过的,真的很神奇。

但还是O(n^2)的真正正解好懂。

先将所有的数排序,sum[i]表示到目前为止这一列上还有多少个数比当前的数大,那么每做一个数,就将这一列上的sum减一。

至于行就倒着再做一遍,最后的代价就是行上的花费+列上的花费。

其实我也很难讲清楚辣真烦,看代码吧~




#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#define N 2020 
using namespace std;
int n,m,t,a[N][N],sum[N],ans[N*N],min1,min2,minans,cnt,num,k;
struct node{
	int res,x,y;
}q[N*N];
bool cmp(node x,node y){return x.res<y.res;}
int main()
{
	freopen("exciting.in","r",stdin);
	freopen("exciting.out","w",stdout);
	scanf("%d%d%d",&n,&m,&t);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			scanf("%d",&a[i][j]);
			q[++num].res=a[i][j];
			q[num].x=i;q[num].y=j;
		}
	sort(q+1,q+1+num,cmp);
	for(int i=1;i<=m;i++) sum[i]=n;
	min1=n;k=1;
	while(k<=num){
		sum[q[k].y]--;
		if(sum[q[k].y]<min1) min1=sum[q[k].y];
		if(q[k].res!=q[k+1].res || k==num) ans[++cnt]=min1;
		k++;
	}
	k=num;
	for(int i=1;i<=n;i++) sum[i]=m;
	min2=m;minans=1<<30-1;
	cnt++;
	while(k){
		sum[q[k].x]--;
		if(sum[q[k].x]<min2) min2=sum[q[k].x];
		if(q[k].res!=q[k-1].res || k==1){
			ans[--cnt]+=min2;
			if(ans[cnt]<minans) minans=ans[cnt];
		}
		k--;
	}
	printf("%d\n",minans);
	return 0;
}


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值