[Codeforces Round #394 DIV2F (CF761F)] Dasha and Photos

题意

给定一个 nm 的字符矩阵,字符集为小写字母。
现在用这个图生成 K 张图,生成方法为:将原图的某一个子矩阵变成相同的某个字符。这样子生成了K张图,要求选择某张图,使得这张图到其它 K1 张图的距离和最小,只输出最小距离和。
两张图的距离定义为对应位置字符ASCll码差的绝对值的和。
n,m103,K3105

题解

设原图中每个位置的字符为 a(i,j)
cnt1(i,j,c) (i,j) 在给定的子矩阵中且变成的字符为 c 的图的个数。
f(i,j)为所有图 (i,j) 位置与原图 (i,j) 位置距离之和: f(i,j)=zc=acnt1(i,j,c)|ca(i,j)|
sum1(i,j) f 矩阵从(1,1) (i,j) 的和: sum1(i,j)=ix=1jy=1f(x,y)
cnt2(i,j,c) (i,j) c 的图的个数(不要求(i,j)在给定子矩阵中)。
sum2(i,j,c) cnt2 矩阵从 (1,1,c) (i,j,c) 的和: sum2(i,j,c)=ix=1jy=1cnt2(x,y,c)

这样之后,枚举每一张图,按如下方法求其他图到它的距离。

  • 对于被改变的子矩阵,枚举其他图在这个子矩阵中的字符,并用 sum2 来求其他图在这个子矩阵中的此字符的位置的个数,同时计算距离加到这张图的答案中。
  • 对于不在被改变的子矩阵中的位置,其他图与这张图的距离相当于所有图与原图的距离,用 sum1 可以求得。

代码

/// by ztx
/// blog.csdn.net/hzoi_ztx

#define Rep(i,l,r) for(i=(l);i<=(r);i++)
#define rep(i,l,r) for(i=(l);i< (r);i++)
#define Rev(i,r,l) for(i=(r);i>=(l);i--)
#define rev(i,r,l) for(i=(r);i> (l);i--)
#define Each(i,v)  for(i=v.begin();i!=v.end();i++)
#define r(x)   read(x)
typedef long long ll ;
typedef double lf ;
int CH , NEG ;
template <typename TP>inline void read(TP& ret) {
    ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;
    if (CH == '-') NEG = true , CH = getchar() ;
    while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;
    if (NEG) ret = -ret ;
}
template <typename TP>inline void readc(TP& ret) {
    while (ret=getchar() , ret<'!') ;
    while (CH=getchar() , CH>'!') ;
}
template <typename TP>inline void reads(TP *ret) {
    ret[0]=0;while (CH=getchar() , CH<'!') ;
    while (ret[++ret[0]]=CH,CH=getchar(),CH>'!') ;
    ret[ret[0]+1]=0;
}

#define  kN  1002LL
#define  kC  26LL
#define  kK  300010LL

#define  infi  0x7f7f7f7f7f7f7f7fLL

struct DATA { int u1, v1, u2, v2, c; } q[kK];

int n, m, K;
int a[kN][kN], str[kN], cnt1[kC][kN][kN];// cnt_changed
ll sum1[kN][kN], sum2[kC][kN][kN];

inline void MI(ll&a, const ll&b) { if (a > b) a = b; }

int main() {
    #define  u1  q[i].u1
    #define  u2  q[i].u2
    #define  v1  q[i].v1
    #define  v2  q[i].v2
    #define  c0  q[i].c
    int i, j, c, tot;
    ll fij, ans, ANS;
    r(n), r(m), r(K);
    Rep (i,1,n) {
        reads(str);
        Rep (j,1,m) a[i][j] = str[j] - 'a';
    }
    Rep (i,1,K) {
        r(u1), r(v1), r(u2), r(v2), readc(c0), c0 -= 'a';
        ++ cnt1[c0][u1][v1];
        -- cnt1[c0][u1][v2+1];
        -- cnt1[c0][u2+1][v1];
        ++ cnt1[c0][u2+1][v2+1];
    }
    Rep (i,1,n) Rep (j,1,m) {
        fij = 0;
        tot = K;
        rep (c,0,26) {
            cnt1[c][i][j] += cnt1[c][i-1][j];
            cnt1[c][i][j] += cnt1[c][i][j-1];
            cnt1[c][i][j] -= cnt1[c][i-1][j-1];
            fij += cnt1[c][i][j] * std::abs(a[i][j]-c);
            tot -= cnt1[c][i][j];
        }
        sum1[i][j] = fij + sum1[i-1][j] + sum1[i][j-1] - sum1[i-1][j-1];
        rep (c,0,26) {
            sum2[c][i][j] = cnt1[c][i][j] + sum2[c][i-1][j] + sum2[c][i][j-1] - sum2[c][i-1][j-1];
            if (a[i][j] == c) sum2[c][i][j] += tot;
        }
    }
    ANS = infi;
    Rep (i,1,K) {
        ans = sum1[n][m] - (sum1[u2][v2]-sum1[u1-1][v2]-sum1[u2][v1-1]+sum1[u1-1][v1-1]);
        rep (c,0,26) {
            ans += (sum2[c][u2][v2]-sum2[c][u1-1][v2]-sum2[c][u2][v1-1]+sum2[c][u1-1][v1-1])*std::abs(c-c0);
        }
        MI(ANS,ans);
    }
    printf("%lld\n", ANS);
    END: getchar(), getchar();
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值