P8253 [NOIO 2022 tg] 如何正确地排序
题面
有一个 \(m\times n\) 的数组 \(a_{i,j}\),定义:
\[f(i,j)=\min\limits_{k=1}^m(a_{k,i}+a_{k,j})+\max\limits_{k=1}^m(a_{k,i}+a_{k,j})
\]
你需要求出 \(\sum\limits_{i=1}^n\sum\limits_{j=1}^nf(i,j)\) 。
数据范围: \(m\le 4,n\le2\times 10^5,a_{i,j}\le 2\times 10^5\) 。
题解
典型考场降智型选手。
想到单独考虑 \(\min,\max\) ,想到考虑每个数产生贡献的次数,为什么不把所有式子都列出来啊...
\[a_i+a_j\le b_i+b_j\\
a_i+a_j\le c_i+c_j\\
a_i+a_j\le d_i+d_j
\]
以 \(a_i+a_j\le b_i+b_j\) 为例:\(a_i+a_j\le b_i+b_j\Leftrightarrow a_i-b_i\le b_j-a_j\) ,所以设 \(A_i=a_i-b_i\) ,\(B_i,C_i\) 同理。
那么原来的式子就变成了:
\[A_i\le -A_j\\
B_i\le -B_j\\
B_i\le -C_j
\]
这你还不会吗?
一些细节:
- 可以把每个元素拆成修改和查询,修改点每个权值取反。
- 防止出现最大值相同而算重,可以给之前已经处理的元素+1。
- 求最大值的式子和上面只有符号的区别,因此可以全部取反再算一次。
void solve(int op){
for(int I=0;I<m;++I){
k=0;
for(int i=1;i<=n;++i){
a[++k].op=A[I][i];
for(int j=0;j<m;++j)
if(j^I)a[k].f[j-(j>I)]=(A[I][i]-A[j][i])*op-(I>j);
a[++k].op=0;
for(int j=0;j<m;++j)
if(j^I)a[k].f[j-(j>I)]=(A[j][i]-A[I][i])*op;
}
sort(a+1,a+1+k,paix);
solve2(1,k);
}
}
启发
- 感觉这种题不要再想一些奇奇怪怪的做法,先老老实实把式子推了,说不定就有解法了。