• 常州模拟赛d8t2 绘画


     

    分析:考虑记录每个坐标上每个颜色出现了几次,并由此算出每个颜色在这个坐标上的贡献。答案肯定是原图的答案扣去矩形的答案,再加上那个矩形同种颜色的贡献,这里的答案指的是Σdis.我们先要记录每个颜色在各个位置出现的次数,因为每一次都是区间操作嘛,所以我们用二维差分可以很好地维护,前缀和求出出现的次数. 然后求出每个位置原本图的和副本的差距,求一下前缀和就得到原本图整体的答案.

    最后再用一个前缀和数组求出每个位置覆盖为颜色x后的贡献,就可以了.

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <cmath>
    
    #define s(u,i,j,k,l) (u[k][l] - u[i-1][l] - u[k][j-1] + u[i - 1][j-1])
    using namespace std;
    
    const int maxn = 1010,maxm = 300010;
    int n, m, kk, rubbish,a[maxn][maxn],sum[30][maxn][maxn],col[maxm];
    int x3[maxm], y3[maxm], x4[maxm], y4[maxm];
    long long ans[maxn][maxn],b[30][maxn][maxn],ret = 1LL << 60,pi;
    char s[maxn];
    
    long long S1(int x, int y, int x2, int y2)
    {
        return ans[x2][y2] - ans[x - 1][y2] - ans[x2][y - 1] + ans[x - 1][y - 1];
    }
    
    long long S2(int cur, int x, int y, int x2, int y2)
    {
        return b[cur][x2][y2] - b[cur][x - 1][y2] - b[cur][x2][y - 1] + b[cur][x - 1][y - 1];
    }
    
    int main()
    {
        scanf("%d%d%d%d", &n, &m, &kk, &rubbish);
        for (int i = 1; i <= n; i++)
        {
            scanf(" %s", s + 1);
            for (int j = 1; j <= m; j++)
                a[i][j] = s[j] - 'a';
        }
        for (int i = 1; i <= kk; i++)
        {
            scanf("%d%d%d%d %c", &x3[i], &y3[i], &x4[i], &y4[i], &col[i]);
            col[i] -= 'a';
            ++sum[col[i]][x3[i]][y3[i]]; //二维差分修改每种颜色出现的次数
            --sum[col[i]][x3[i]][y4[i] + 1];
            --sum[col[i]][x4[i] + 1][y3[i]];
            ++sum[col[i]][x4[i] + 1][y4[i] + 1];
        }
        for (int k = 0; k < 26; k++)
            for (int i = 1; i <= n; i++)
                for (int j = 1; j <= m; j++)
                    sum[k][i][j] += sum[k][i - 1][j] + sum[k][i][j - 1] - sum[k][i - 1][j - 1];//统计每个点每种颜色出现的次数
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
            {
                for (int k = 0; k < a[i][j]; k++)
                    ans[i][j] += sum[k][i][j] * (a[i][j] - k);//每一位对dis的贡献值
                for (int k = 25; k > a[i][j]; k--)
                    ans[i][j] += sum[k][i][j] * (k - a[i][j]);
                ans[i][j] += ans[i - 1][j] + ans[i][j - 1] - ans[i - 1][j - 1];//记录整个图的dis
            }
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
            {
                int t = 0;
                for (int k = 0; k < 26; k++)
                    t += sum[k][i][j];
                sum[a[i][j]][i][j] += kk - t;//之前记录的是副本上出现的次数,现在记录原有的出现次数
            }
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
            {
                int s1 = 0, s2 = 0;
                for (int k = 0; k < 26; k++)
                {
                    s1 += sum[k][i][j] * k;
                    s2 += sum[k][i][j];
                    b[k][i][j] = s2 * k - s1; //如果我把每个副本(i,j)上的点全部变成k的贡献
                }
                s1 = s2 = 0;
                for (int k = 25; k >= 0; k--)//相当于计算ans,倒着计算一次
                {
                    s1 += sum[k][i][j] * k;
                    s2 += sum[k][i][j];
                    b[k][i][j] += s1 - s2 * k;
                }
                for (int k = 0; k < 26; k++)
                    b[k][i][j] += b[k][i - 1][j] + b[k][i][j - 1] - b[k][i - 1][j - 1];
            }
        for (int i = 1; i <= kk; i++)
        {
            long long temp = ans[n][m] - s(ans, x3[i], y3[i], x4[i], y4[i]) + s(b[col[i]], x3[i], y3[i], x4[i], y4[i]);
            if (temp < ret)
            {
                ret = temp;
                pi = i;
            }
        }
        printf("%lld %d
    ", ret, pi);return 0;
    }

     

  • 相关阅读:
    137. 只出现一次的数字 II
    JS_利用Canvas进行图片旋转
    JS_图片压缩并预览
    计蒜客——等和的分隔子集
    中缀表达式转后缀并计算(只考虑个位整数,不考虑除0等情况)
    求最小数 * 区间和最大值
    967 质量检测
    PAT-1102(Invert a Binary Tree)
    PAT-1100(Mars Numbers)
    PAT-1099(Build A Binary Search Tree)
  • 原文地址:https://www.cnblogs.com/zbtrs/p/7616574.html
Copyright © 2020-2023  润新知