常州模拟赛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\n", ret, pi);return 0;
}

 

时间: 2024-11-09 00:51:51

常州模拟赛d8t2 绘画的相关文章

常州模拟赛d3t2 灰狼呼唤着同胞

题目背景 我的母亲柯蒂丽亚,是一个舞者.身披罗纱,一身异国装扮的她,来自灰狼的村子. 曾经在灰狼村子担任女侍的她,被认定在某晚犯下可怕的罪行之后,被赶出了村子. 一切的元凶,都要回到母亲犯下重罪的那一晚. 题目描述 我不认为柯蒂丽亚有犯罪. 二十年前的混沌,一共有n块碎片. 这n块碎片曾经两两之间都有联系,可是很多联系都在时间的洪流中消失了. 现在,我只能确定其中m条联系的种类. 每条联系都是一条无向边,任意两块碎片之间至多有一条联系,没有联系会连接在同一块碎片的两端. 联系有两种.一种是冲突,

bzoj3743 [Coci2015]Kamp 常州模拟赛d6t2

3743: [Coci2015]Kamp Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 484  Solved: 229[Submit][Status][Discuss] Description 一颗树n个点,n-1条边,经过每条边都要花费一定的时间,任意两个点都是联通的. 有K个人(分布在K个不同的点)要集中到一个点举行聚会. 聚会结束后需要一辆车从举行聚会的这点出发,把这K个人分别送回去. 请你回答,对于i=1~n,如果在第i个点举行聚会,司

常州模拟赛d5t2 mogician

分析:一个暴力的思想是枚举g,然后枚举每个数ai,看能不能符合要求,这样复杂度是O(nA)的,直接T掉了.也没什么其他的办法了,在暴力的基础上优化一下,优化的关键是要如何快速统计出不满足要求的数的个数.利用数据结构?想不到.仔细分析一下,不满足要求的数组成了很多区间,每次i枚举g的倍数,不满足要求的数的区间总在[i + k + 1,i + g - 1]中,因为i+k+1通过减k满足不了要求,i+g-1比g的倍数少了1,那么利用前缀和数组维护一下个数就好了.不过有一种特殊情况:k >= g - 1

常州模拟赛d5t1 journalist

分析:出题人丧心病狂卡spfa......只能用dijkstar+堆优化. 主要的难点是字典序的处理上,一个想法是在做最短路的时候处理,边松弛边记录,比个大小记录最佳答案.具体的思路大概和最短路计数差不多,当遇到d[u] + w[i] == d[v]是,说明到d[v]有两条最短路了,更新一下答案. 但是这样效率太低了,每一次松弛都要更新一次,能不能一次性更新完呢?可以的.我们在跑完最短路后把满足d[u] + w[i] == d[v]的点v加入u的邻接表中,排个序,然后dfs一遍就好了. #inc

常州模拟赛d2t1 小X的质数

题目背景 小 X 是一位热爱数学的男孩子,在茫茫的数字中,他对质数更有一种独特的 情感.小 X 认为,质数是一切自然数起源的地方. 题目描述 在小 X 的认知里,质数是除了本身和 1 以外,没有其他因数的数字. 但由于小 X 对质数的热爱超乎寻常,所以小 X 同样喜欢那些虽然不是质数, 但却是由两个质数相乘得来的数. 于是,我们定义,一个数是小 X 喜欢的数,当且仅当其是一个质数,或是两 个质数的乘积. 而现在,小 X 想要知道,在 L 到 R 之间,有多少数是他喜欢的数呢? 输入输出格式 输入

常州模拟赛d7t1 亲戚

分析:把题目换个方式理解,就是把各个点排成一列,并且指定了若干对的先后次序,问你有多少种序列满足要求. 显然是一道dp题,直接推出方程似乎有点点困难,那么先看看数据特点. 1.有一些点满足fi=0,那么直接输出n!就可以了. 2.保证所有的关系是一条链.我们假设所有链的长度和为sum,链1的长度为l1,链2的长度为l2...... 现在有sum个位置,我要把链1上的点按照次序放到sum个位置上,一共有C(sum,l1)种方案,接下来放链2,还有sum - l1个位置,所以有C(sum - l1,

常州模拟赛d5t3 appoint

分析:这道题比较奇葩.因为字符串没有swap函数,所以一个一个字符串交换只有30分.但是我们可以不用直接交换字符串,而是交换字符串的指针,相当于当前位置是哪一个字符串,每次交换int,可以拿60分. 对于二维问题,通常转化为一维问题去考虑,得到适当的方法再应用到二维上来,这道题如果转移到一维上就是给你一个序列,每次交换一对区间,区间不重叠,最后要求顺序输出整个序列,很显然,我们只要记录每个数旁边的数就好了,所以用链表能很快解决.转化到二维上,我们记录一个右方的链表,下方的链表,每次交换操作只需要

常州模拟赛d7t3 水管

分析:第一问还是很好做的,关键是怎么做第二问.我们可以每次删掉最小生成树上的一条边,然后再求一次最小生成树,看边权和大小和原来的是不是一样的,不过这个做法效率很低. 考虑Kruskal算法的原理,每次加边权最小的边,如果边上的两个点不连通.如果在最小生成树的基础上把不是上面的边给加上去,就会形成环,在环上找除了这条边之外的最大边权,如果等于新加入的这条边,那么就有多个最小生成树.为什么这样呢?我们把最大边拿掉,添加进这条边,两个点还是连通的,边权和一定,只是在Kruskal的时候先考虑了那条最大

【BZOJ】【2741】【FOTILE模拟赛】L

可持久化Trie+分块 神题……Orz zyf & lyd 首先我们先将整个序列搞个前缀异或和,那么某一段的异或和,就变成了两个数的异或和,所以我们就将询问[某个区间中最大的区间异或和]改变成[某个区间中 max(两个数的异或和)] 要是我们能将所有[l,r]的答案都预处理出来,那么我们就可以O(1)回答了:然而我们并不能. 一个常见的折中方案:分块! 这里先假设我们实现了一个神奇的函数ask(l,r,x),可以帮我们求出[l,r]这个区间中的数,与x最大的异或值. 我们不预处理所有的左端点,我