2017模拟赛 现代艺术(二维差分)

博客探讨了现代艺术创作中的一种独特方式,通过二维差分来解析艺术家何老板的画作。何老板在N×N的画布上,用1到N²的数字填充子矩阵,每个数字仅使用一次。问题在于,根据最后的画作,找出第一步可能使用的数字数量。文章提供了输入输出格式,题解思路以及代码实现。

何老板是一个现代派的艺术家。他在一块由n*n的方格构成的画布上作画。一开始,所有格子里的数字都是0。
何老板作画的方式很独特,他先后给N^2个子矩阵涂上了颜色,每次都是从1到N^2这些数字中选一个给对应矩阵全部填上该数字。比如:
第1步,他选数字2填在了一个子矩阵上。如下图:

2 2 2 0 2 2 2 0 2 2 2 0 0 0 0 0 第2步,他用数字7填在了一个子矩阵上: 2 2 2 0 2 7 7
7 2 7 7 7 0 0 0 0 第3步,他用数字3填在了一个子矩阵上: 2 2 3 0 2 7 3 7 2 7 7 7 0 0
0 0 以此填涂下去,直到1到N^2中每个数字都被用过了一次(每个数字只能被使用一次)。
现在何老板已经完成了他的艺术创作,你得到了最后的图形。
何老板问你,根据这幅作品,你能够推断出第一步填涂的数字可能是哪些呢?输出第一步填涂可能的数字的个数。

输入格式

第一行,一个整数N(1<=N<=1000) 接下来一个N*N的数字矩阵,表示画作最终的样子。

输出格式

一个整数,表示第一步填涂可能的数字个数。

题解

统计每种颜色所覆盖的数量,如果一个点被两个点所覆盖,那么最上面的颜色一定不可能是最先被涂的

代码

#include<stdio.h>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<queue>
using namespace std;
#define maxn 1001
int a[maxn][maxn];
int cn[maxn][maxn],Cnt[maxn][maxn];
int U[maxn*maxn],D[maxn*maxn],L[maxn*maxn],R[maxn*maxn];
int s[maxn][maxn];
int cnt;
bool mark[maxn*maxn];
bool mark2[maxn*maxn];
int n;
int main()
{
    int i,j,k;
    scanf("%d",&n);
    for(i=1;i<=n*n;i++) U[i]=L[i]=1e9;
    for(i=1;i<=n;i++)
     {
        for(j=1;j<=n;j++)
        {
            scanf("%d",&a[i][j]);
            if(a[i][j]){
                U[a[i][j]]=min(U[a[i][j]],i);
                D[a[i][j]]=max(D[a[i][j]],i);
                L[a[i][j]]=min(L[a[i][j]],j);
                R[a[i][j]]=max(R[a[i][j]],j);
             if(!mark[a[i][j]]){
                cnt++;
                mark[a[i][j]]=true;
             } 
            }
         }
     }
     if(cnt==0){cout<<n*n;return 0;}
     if(cnt==1){cout<<n*n-1;return 0;}
    for(i=1;i<=n*n;i++){
        if(mark[i]){
             cn[U[i]][L[i]]+=1;
             cn[D[i]+1][L[i]]-=1;
             cn[U[i]][R[i]+1]-=1;
             cn[D[i]+1][R[i]+1]+=1;     
        }
    }
    int tot=0;
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=n;j++)
        {
            Cnt[i][j]=cn[i][j]+Cnt[i-1][j]+Cnt[i][j-1]-Cnt[i-1][j-1];
            if(Cnt[i][j]>1){
                if(mark2[a[i][j]]==false){
                    mark2[a[i][j]]=true;
                    tot++;
               }
            }   
         }
    }
    cout<<n*n-tot;
}

<think>嗯,用户想了解蓝桥杯中的差分算法。首先,我得先回忆一下差分的基本概念和应用场景。差分主要用于处理数组区间修改的问题,比如多次对数组的某个区间进行加减操作,最后再查询结果。这种方法可以大幅降低时间复杂度,从O(n)降到O(1)的每次操作,最后再通过前缀和恢复数组。 接下来,我需要考虑蓝桥杯比赛中常见的差分题型。通常这类题目会涉及到多次区间修改,比如给某个区间内的所有元素加上一个值,然后询问最终数组的状态或者某些特征值。例如,可能有一道题是给一个数组,进行m次操作,每次操作对区间[l, r]加k,最后求数组的最大值或者某个位置的数值。这时候使用差分就能高效解决。 然后,我需要整理差分的基本步骤。差分数组的构建是通过原数组相邻元素的差来生成的。具体来说,差分数组d[i] = a[i] - a[i-1],其中a是原数组。这样,当需要对原数组的区间[l, r]加上k时,只需要对差分数组的d[l] += k,d[r+1] -= k即可。最后通过前缀和操作还原原数组。 可能还需要举一个具体的例子来演示这个过程。比如原数组是[1, 3, 5, 7, 9],对应的差分数组是[1, 2, 2, 2, 2]。假设要在区间[2,4](假设索引从1开始)加上3,那么差分数组的第二个元素加3,第五个元素减3,得到新的差分数组[1,5,2,2,-1]。然后通过前缀和得到原数组变为[1,6,8,10,9]。这样用户更容易理解差分的作用。 另外,需要注意边界条件,比如当r是数组最后一个元素时,r+1可能会超出数组范围,这时候可以忽略对d[r+1]的操作,或者在差分数组长度设为n+1来避免越界。这点在实现时需要特别注意,否则会导致错误。 还要考虑时间和空间复杂度分析。差分法的初始构建需要O(n)时间,每次区间操作是O(1),最后恢复原数组需要O(n)时间,总的时间复杂度是O(n + m),其中m是操作次数。这比暴力法的O(mn)要好很多,尤其是在大规模数据的情况下。 可能还需要提到二维差分,虽然用户没有问,但如果有余力的话可以简要说明,但用户的问题主要集中在差分,所以可能暂时不需要深入二维的情况。 另外,蓝桥杯中的题目可能会有变种,比如结合前缀和、贪心算法或者其他数据结构一起使用。需要提醒用户注意题目的具体要求,灵活应用差分技巧。例如,有些题目可能需要先进行多次区间修改,然后进行查询,这时候差分就能高效处理。 最后,给出一个例题和代码示例会更有帮助。比如,假设题目是给定一个长度为n的数组,初始全为0,进行m次操作,每次操作对区间[l, r]加k,最后输出最终的数组。这时候可以用Python代码演示如何实现差分数组的构建、修改和恢复过程。 总结一下,回答的结构应该是先介绍差分的基本概念,然后说明其应用场景,详细步骤,举例说明,注意点,以及例题和代码。这样用户能够逐步理解并应用差分算法解决蓝桥杯中的相关问题。</think>### 蓝桥杯差分算法详解 #### 1. **差分的基本概念** 差分是一种**数组区间高效修改**的技术,常用于处理多次区间增减操作后求最终数组的问题。其核心思想是通过**差分数组**将区间操作的时间复杂度从$O(n)$优化到$O(1)$。 #### 2. **差分的作用场景** - **典型问题**:给定数组$a$,进行$m$次操作,每次对区间$[l, r]$加上值$k$,最后求数组$a$的结果。 - **暴力法缺点**:直接遍历区间修改,时间复杂度为$O(mn)$,无法通过大规模数据。 - **差分优势**:通过预处理差分数组,将每次操作优化为$O(1)$,总时间复杂度$O(n + m)$。 --- #### 3. **差分数组的构建** - **定义**差分数组$d$满足: $$d[i] = a[i] - a[i-1] \quad (i \geq 1)$$ $$d[0] = a[0] \quad (i=0)$$ - **逆向恢复**:对差分数组求前缀和即可还原原数组: $$a[i] = d[0] + d[1] + \dots + d[i]$$ --- #### 4. **区间修改的核心操作** 若要对原数组$a$的区间$[l, r]$加上$k$,只需修改差分数组的两处: 1. **起点**:$d[l] += k$(使得前缀和从$l$开始增加$k$) 2. **终点后一位**:$d[r+1] -= k$(抵消$r+1$之后的影响) --- #### 5. **操作示例** **原数组**:$a = [1, 3, 5, 7, 9]$,对应的差分数组$d = [1, 2, 2, 2, 2]$ **操作**:对区间$[2, 4]$(索引从1开始)加3 **修改差分数组**: - $d[2] += 3$ → $d = [1, 2+3, 2, 2, 2]$ - $d[5] -= 3$(若数组长度允许) → $d = [1, 5, 2, 2, -1]$ **恢复原数组**: $a' = [1, 1+5=6, 6+2=8, 8+2=10, 10+(-1)=9]$ --- #### 6. **边界处理技巧** - **数组越界**:若$r$是最后一个元素,无需操作$d[r+1]$(或定义差分数组长度为$n+1$)。 - **索引对齐**:注意题目中的区间是**从0还是1开始**,避免偏移错误。 --- #### 7. **代码实现(Python)** ```python n = 5 # 数组长度 m = 1 # 操作次数 a = [0] * (n + 2) # 差分数组(多开空间防越界) # 模拟操作:对区间[2,4]加3(假设索引从1开始) l, r, k = 2, 4, 3 a[l] += k a[r + 1] -= k # 求前缀和还原原数组 for i in range(1, n + 1): a[i] += a[i - 1] print("最终数组:", a[1:n+1]) # 输出: [0, 3, 3, 3, 0](若初始全0) ``` --- #### 8. **蓝桥杯真题应用** - **例题特点**:通常结合“区间修改+最终极值/总和”考查。 - **真题示例****问题**:给定长度为$n$的数组,初始全0,进行$m$次区间加操作,求最终数组的最大值。 **解法**:用差分记录所有操作后,求前缀和并遍历找最大值。 --- #### 9. **扩展:二维差分** 对于二维数组的区间修改(如矩阵块加减),可通过二维差分实现$O(1)$操作,但蓝桥杯较少涉及。 --- #### 总结 差分是蓝桥杯高频考点,需掌握**差分数组构建、区间修改公式、边界处理**。重点练习“多次操作后求数组状态”类题目。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值