zoukankan      html  css  js  c++  java
  • 题解 【[MdOI2020] Decrease】

    [ exttt{Preface} ]

    感觉 C 比 B 还简单?

    [ exttt{Description} ]

    给定一个 (n×n) 的矩阵,你可以进行若干次操作。

    每次操作,你可以将一个 (k×k)连续 子矩阵里的所有数全都加上 (1) 或者全部都减去 (1)

    初始时,矩阵中有 (m) 个位置上的数不为 (0) ,其他位置上的数均为 (0)

    请你求出至少需要多少次操作,可以将矩形中所有数都变为 (0)

    [ exttt{Solution} ]

    为了方便叙述,我们称原矩阵为 (A)

    (~)

    Subtask1 : (n leq 10^3)(k leq 1)

    很显然,答案为 (sumlimits_{i=1}limits^{n}sumlimits_{j=1}limits^{n}|A[i][j]|)

    至此能拿到 (11pts)

    (~)

    Subtask2 : (n leq 20)(k leq 20)

    我不知道怎么艹过这个子任务欸 qwq 。

    理论上是留给暴力选手的。

    至此能拿到 (25pts)

    (~)

    Subtask3 : (n leq 100)(k leq 100)

    有点正解的味道了。

    首先我们注意到操作的顺序不会影响答案,且一个 (k×k) 的子矩阵不能一会加一会减。

    (~)

    考虑 A[1][1] ,它显然只会被一个 (k×k) 的子矩阵覆盖(一个左上 ((1,1)) ,右下 ((k,k)) 的子矩阵),那么我们只能通过该矩阵来控制 A[1][1]

    那我们直接使得该矩阵中的所有元素减去 A[1][1] 即可,我们就要保证该矩阵不能再被操作了。

    接着考虑 A[1][2] ,它只会被两个 (k×k) 的子矩阵覆盖(一个左上 ((1,1)) ,右下 ((k,k)) 的子矩阵,一个左上 ((1,2)) ,右下 ((k,k+1)) 的子矩阵),但是我们要保证左上 ((1,1)) ,右下 ((k,k)) 的子矩阵不能被操作,否则就破坏了 A[1][1],所以我们只能通过左上 ((1,2)) ,右下 ((k,k+1)) 的子矩阵来控制 A[1][2]

    直接使得该矩阵所有元素减去 A[1][2] 即可。

    以此类推,对于 ((i,j)) 满足 (i,j leq n-k+1) 的位置,都能按顺序控制 **左上 ((i,j)) ,右下 ((i+k-1,j+k-1)) ** 的子矩阵使得 A[i][j] = 0 ,即令该矩阵所有元素减去 A[i][j] 即可。

    那么对于剩下的 ((i,j)) 不满足 (i,j leq n-k+1) 的位置,则已经不能改变 A[i][j] 的值了,所以说,若在这些位置中找到一个 A[i][j] ≠ 0 ,则说明无解。

    暴力去修改矩阵,时间复杂度 (O(k^2(n-k)^2))由小学数学可得,当 (k=frac{n}{2}) 时,复杂度最高,为 (O(frac{n^4}{16})) ,计算量约为 (6250000) ,稳的一批。

    至此能拿到 (42pts)

    (~)

    Subtask4 : (n leq 10^3)(k leq 10^3)

    我们发现对矩阵做减法操作可以用一维差分优化到 (O(k))

    具体的,开个一位差分数组 S[i][j] ,每次令 **左上 ((i,j)) ,右下 ((i+k-1,j+k-1)) ** 的矩阵减去 (d) 时,我们只需要令 S[i~i+k-1][j] += d, S[i~i+k-1][j+k] -= d 即可,记得在枚举的过程中要用一维前缀和还原当前状态的 (S) 数组。

    时间复杂度 (O(k(n-k)^2))由小学数学可得,当 (k=frac{n}{3}) 时,复杂度最高,为 (O(frac{4n^3}{27})) ,计算量约为 (148148148) ,没有亲测过,开个 ( ext{O2}) 应该稳。

    至此能拿到 (76pts)

    (~)

    Subtask5 : (n leq 5×10^3)(k leq 10^3)

    能一维差分干嘛不能二维差分阿

    我们发现对矩阵做减法操作可以用二维差分优化到 (O(1))

    具体的,开个一位差分数组 S[i][j] ,每次令 **左上 ((i,j)) ,右下 ((i+k-1,j+k-1)) ** 的矩阵减去 (d) 时,我们只需要令 S[i][j] += d, S[i+k][j] -= d, S[i][j+k] -= d, S[i+k][j+k] += d 即可,记得在枚举的过程中要用二维前缀和还原当前状态的 (S) 数组。

    时间复杂度 (O((n-k)^2)) ,稳的一批。

    至此能拿到 (100pts)

    [ exttt{Code} ]

    #include<cstdio>
    #include<algorithm>
    
    #define RI register int // 卡常1
    
    using namespace std;
    
    namespace IO // 卡常2
    {
        static char buf[1<<20],*fs,*ft;
        inline char gc()
        {
            if(fs==ft)
            {
    			ft=(fs=buf)+fread(buf,1,1<<20,stdin);
    			if(fs==ft)return EOF;
            }
            return *fs++;
        }
        #define gc() getchar()
    	inline int read()
    	{
    		int x=0,f=1;char s=gc();
    		while(s<'0'||s>'9'){if(s=='-')f=-f;s=gc();}
    		while(s>='0'&&s<='9'){x=x*10+s-'0';s=gc();}
    		return x*f;
    	}
    }using IO::read;
    
    const int N=5010;
    
    int n,m,k;
    
    long long a[N][N];
    long long S[N][N];
    
    long long ans;
    
    int main()
    {
    	n=read(),m=read(),k=read();
    
    	for(RI i=1;i<=m;i++)
    	{
    		int x=read(),y=read(),d=read();
    		a[x][y]=d;
    	}
    
    	for(RI i=1;i<=n;i++)
    		for(RI j=1;j<=n;j++)
    		{
    			S[i][j]=S[i][j]+S[i-1][j]+S[i][j-1]-S[i-1][j-1];
    			a[i][j]+=S[i][j];
    
    			if(i+k-1>n||j+k-1>n)
    			{
    				if(a[i][j]==0)
    					continue;
    				else
    				{
    					puts("-1");
    					return 0;
    				}
    			}
    
    			ans+=abs(a[i][j]);
    			S[i][j]+=-a[i][j];
    			S[i+k][j]-=-a[i][j];
    			S[i][j+k]-=-a[i][j];
    			S[i+k][j+k]+=-a[i][j];
    		}
    
    	printf("%lld
    ",ans);
    
    	return 0;
    } 
    

    [ exttt{Thanks} exttt{for} exttt{watching} ]

  • 相关阅读:
    18、排序算法-快速排序
    centos7.x 端口映射
    SpringBoot多环境分离resources和lib进行打包
    Java枚举储存的一种索引实现方式
    Maven项目pom文件设置JDK版本
    Java提取URL某个参数的值
    使用正则替换script及其内容
    Oracle设置主键自增
    Maven配置ojdbc14-10.2.0.4.0.jar
    使用maven生成可执行jar包(包含依赖)
  • 原文地址:https://www.cnblogs.com/cjtcalc/p/12289014.html
Copyright © 2011-2022 走看看