×

第十四篇:AT_abc476_f

题解补完计划:第十四篇(为什么被打回了?,洛谷护佑我。
原题题面

简要题意

每个格子 \((i,j)\) 的人数为 \((A_i \times B_j) \bmod M\) 。住在单元格 \((s_r,s_c)\) 的一名与会者去单元格 \((t_r,t_c)\) 的咖啡馆的交通费用为 \(\max(|s _ r - t _ r|, |s _ c - t _ c|)\) 。

定义 \(f_{(i, j)}\) 为将所有参与者聚集到位于 \((i, j)\) 小区的咖啡馆所产生的旅行总费用。

求所有的下面的值并异或起来。

  • \(f(i,j) + (i-1)N + (j-1)\)

思路

我们先把切比雪夫距离变为曼哈顿距离:

令 \(i_x = \frac{i_r+i_c}{2}, i_y = \frac{i_r-i_c}{2}\)
那么有:

\[\max(|s_r-t_r|,|s_c-t_c|) = |s_x - t_x| + |s_y-t_y| \]

那么两个点之间的距离就变为横纵坐标之差相加,令 \(g_x\) 表示横坐标为 \(x\) 时距离之和,从 \(g_x\) 到 \(g_{x+1}\),我们发现对于小于 \(x+1\) 的位置距离都增加了 \(1\),而大于等于的位置都减少了 \(1\),考虑维护前缀和 \(sum_i\) 表示横坐标小于等于 \(i\) 的总人数,我们发现 \(g_{x+1} = g_x + sum{x} - (sum_n - sum_x)\),\(O(n)\) 递推即可,对与纵坐标同理,最后加起来求值即可。

总时间复杂度 \(O(n^2)\)。

代码:

#include<bits/stdc++.h>
using namespace std;
#define N 1505
#define intl long long
#define For(i,a,b) for(intl i=a;i<=b;i++)
#define deo(i,a,b) for(intl i=a;i>=b;i--)
intl read() {
	intl x=0,k=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch == '-') k=-1;ch=getchar();}
	while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*k;
}
intl n,m,a[N],b[N];
intl c[2][N<<1],f[2][N<<1];
void calc(intl k) {
	intl len=2*n-1,sum=0,pre=0;
	f[k][1]=0;
	For(i,1,len) sum += c[k][i], f[k][1] += c[k][i]*(i-1);
	For(i,2,len) pre += c[k][i-1], f[k][i] = f[k][i-1]+pre-(sum-pre);
}
int main() {
	n=read(),m=read();
	For(i,1,n) a[i]=read();
	For(i,1,n) b[i]=read();
	For(i,1,n) For(j,1,n) {
		intl w=a[i]*b[j]%m;
		c[0][i+j-1] += w, c[1][i-j+n] += w;
	}
	calc(0), calc(1);
	intl ans = 0;
	For(i,1,n) For(j,1,n) ans ^= ((f[0][i+j-1]+f[1][i-j+n])/2+(i-1)*n+(j-1));
	printf("%lld\n",ans);
	return 0;
}

代码中使用先乘 \(2\) 以避免浮点数误差。

posted @ 2026-10-05 17:31  shiori123  阅读(5)  评论(0)    收藏  举报