题意
给定一个n⋅m的字符矩阵,字符集为小写字母。 现在用这个图生成K张图,生成方法为:将原图的某一个子矩阵变成相同的某个字符。这样子生成了K张图,要求选择某张图,使得这张图到其它K−1张图的距离和最小,只输出最小距离和。 两张图的距离定义为对应位置字符ASCll码差的绝对值的和。 n,m≤103,K≤3⋅105
题解
设原图中每个位置的字符为a(i,j)。 设cnt1(i,j,c)为(i,j)在给定的子矩阵中且变成的字符为c的图的个数。 设f(i,j)为所有图(i,j)位置与原图(i,j)位置距离之和:f(i,j)=∑′z′c=′a′cnt1(i,j,c)⋅|c−a(i,j)|。 设sum1(i,j)为f矩阵从(1,1)至(i,j)的和:sum1(i,j)=∑ix=1∑jy=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=1∑jy=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 0x7f7f7f7f7f7f7f7fLLstruct DATA { int u1, v1, u2, v2, c; } q[kK];int n, m, K;int a[kN][kN], str[kN], cnt1[kC][kN][kN];// cnt_changedll 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;}