lambda QAQ

fmap :: (q -> a) -> f q -> f a

Codeforces Round 761F - Dasha and Photos

给出一个n×m的只包含小写字母的矩阵A

k次独立的操作,每次把原矩阵的某个子矩阵用一个字母覆盖得到一个矩阵Ax(称之为特殊矩阵)。

定义AxAy的距离dis(Ax,Ay)=1in,1jm|Axi,jAyi,j|

min1xk{1ym,yxdis(Ax,Ay)}


对于前缀和的应用真是excited

cnt统计的是所有的special矩阵对应位置的字母个数

用原矩阵拿来算贡献放到val里

然后枚举special

对每个special非子矩阵的位置就是所有贡献-子矩阵的贡献(这部分通过预处理出val的前缀和可以O(1)做)

然后长方形的位置的贡献枚举字母通过cnt的前缀和得到字母在子矩阵出现的次数O(26)计算

这样就在O(26×n×m+26×k)的时间复杂度内解决了本题


#include<bits/stdc++.h>
using namespace std;

#define LL long long 
const LL INF = 0x3f3f3f3f3f3f3f3fll;
const int maxn = 1123;

void integral(LL arr[maxn][maxn],int n,int m){
    for(int i = 1 ; i <= n ; i++){
        for(int j = 1 ; j <= m ; j++){
            arr[i][j] += arr[i-1][j];
            arr[i][j] += arr[i][j-1];
            arr[i][j] -= arr[i-1][j-1];
        }
    }
}

void derivative(LL arr[maxn][maxn],int n,int m){
    for(int i = n ; i >= 1 ; i --){
        for(int j = m ; j >= 1 ; j--){
            arr[i][j] -= arr[i-1][j];
            arr[i][j] -= arr[i][j-1];
            arr[i][j] += arr[i-1][j-1];
        }
    }
}

void add(LL arr[maxn][maxn],int sx,int mx,int sy,int my){
    arr[mx+1][my+1]++; 
    arr[mx+1][sy+1]--;
    arr[sx+1][my+1]--;
    arr[sx+1][sy+1]++;
}

LL sum(LL arr[maxn][maxn],int sx,int mx,int sy,int my){
    return arr[mx][my] 
          -arr[mx][sy] 
          -arr[sx][my] 
          +arr[sx][sy];
}

LL cnt[26][maxn][maxn],times[maxn][maxn];

LL que(int c,int sx,int mx,int sy,int my){
    LL ret = 0;
    for(int z = 0 ; z < 26 ; z++){
        ret += abs(c - z) * sum(cnt[z],sx,mx,sy,my);
    }
    return ret;
}

LL val[maxn][maxn];
int inp[maxn][maxn];
char input[maxn];

const int maxm = 312345;
int a[maxm],b[maxm],c[maxm],d[maxm],e[maxm];

int main(){
    int n,m,k;
    scanf("%d %d %d",&n,&m,&k);
    for(int i = 1 ; i <= n ; i++){
        scanf("%s",input+1);
        for(int j = 1 ; j <= m ; j++){
            inp[i][j] = input[j] - 'a';
        }
    }
    memset(times,0,sizeof(times));
    for(int i = 0 ; i < k ; i++){
        scanf("%d %d %d %d %s",&a[i],&b[i],&c[i],&d[i],input);
        a[i]--,b[i]--; 
        e[i] = *input - 'a';
        add(times,a[i],c[i],b[i],d[i]);
    }
    integral(times,n,m);

    memset(cnt,0,sizeof(cnt));
    for(int i = 1; i <= n ; i++){
        for(int j = 1 ; j <= m ; j++){
            cnt[inp[i][j]][i][j] += k - times[i][j];
        }
    }
    for(int z = 0 ; z < 26 ; z++) 
        derivative(cnt[z],n,m);

    for(int i = 0 ; i < k ; i++)
        add(cnt[e[i]],a[i],c[i],b[i],d[i]);

    for(int z = 0 ; z < 26 ; z++) 
        integral(cnt[z],n,m);
    memset(val,0,sizeof(val));
    for(int i = 1 ; i <= n ; i++){
        for(int j = 1 ; j <= m ; j++){
            for(int z = 0 ; z < 26 ; z++){
                val[i][j] += cnt[z][i][j] * abs(z - inp[i][j]);
            }
        }
    }
    integral(val,n,m);
    for(int z = 0 ; z < 26 ; z++) 
        integral(cnt[z],n,m);
    LL ans = INF;

    for(int i = 0 ; i < k ; i ++){
        ans = min(ans,val[n][m] 
                     -sum(val,a[i],c[i],b[i],d[i]) 
                     +que(e[i],a[i],c[i],b[i],d[i]));
    }
    printf("%I64d\n",ans);
    return 0;
}

总结一下

在差分下我们可以更新区间

原数组下可以单点更新 单点询问

在前缀和下可以区间查询

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a1s4z5/article/details/54846673
个人分类: --数据结构---
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭