T1.matrix
多次询问A*B的区间和
不考虑naive地乘出来,画个图就能发现,总是A的一些列,乘以B的一些行。
维护多行多列的前缀和,就可以做了
时间复杂度O(nm)

#include<iostream>
#include<cstdio>
#define R register
using namespace std;
inline int rd(){
int ret=0,f=1;char c;
while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
while(isdigit(c))ret=ret*10+c-'0',c=getchar();
return ret*f;
}
const int MAXN=2048;
int n,m;
int a[MAXN*MAXN],b[MAXN*MAXN];
long long sa[MAXN*MAXN],sb[MAXN*MAXN];
int main(){
freopen("matrix.in","r",stdin);
freopen("matrix.out","w",stdout);
n=rd();m=rd();
for(R int i=1;i<=n;i++)
for(R int j=1;j<=n;j++)
a[(i<<11)+j]=rd();
for(R int i=1;i<=n;i++)
for(R int j=1;j<=n;j++)
b[(i<<11)+j]=rd();
for(R int i=1;i<=n;i++){
for(R int j=1;j<=n;j++){
sa[(i<<11)+j]=sa[(i<<11)+j-1]+a[(j<<11)+i];//i row j line
sb[(i<<11)+j]=sb[(i<<11)+j-1]+b[(i<<11)+j];//i line j row
}
}
int x,y,u,v;
long long ans=0;
for(R int i=1;i<=m;i++){
ans=0;
x=rd();y=rd();u=rd();v=rd();
if(x>u)swap(x,u);if(y>v)swap(y,v);
for(int j=1;j<=n;j++)
ans+=1ll*(sa[(j<<11)+u]-sa[(j<<11)+x-1])*1ll*(sb[(j<<11)+v]-sb[(j<<11)+y-1]);
printf("%lld
",ans);
}
return 0;
}
T2.tower
写了模拟退火,初始状态集合设的二元组(x,y),x∈{所有x},y∈{所有y},发现跑的很稳定,很快
原因是,答案就一定在这些点里啊!
如果一个点的横纵坐标都不曾出现的话,那它就不和任何一个点在同一行、列,这样的情况是不优秀的。
而本题求的是曼哈顿距离,可以证明,这些初始集合里的这些二元组,一定不是劣解。
暴力跑一跑就可以了。(迷途知返)

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<vector>
#include<cmath>
#define id(x,y) ((x)*(n+1)+(y))
#define R register
using namespace std;
inline int rd(){
int ret=0,f=1;char c;
while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
while(isdigit(c))ret=ret*10+c-'0',c=getchar();
return ret*f;
}
const int MAXN=64;
//const double COOL=0.98;
//const double eps=1e-6;
struct Point{
int x,y;
Point(int u=0,int v=0){x=u;y=v;}
}po[MAXN];
inline int dis(int x,int y,int u,int v){
return abs(x-u)+abs(y-v);
}
int n;
int xs[MAXN],ys[MAXN],totx,toty;
vector<int> ans[MAXN*MAXN];
int sum[MAXN][MAXN][MAXN];
int main(){
freopen("tower.in","r",stdin);
freopen("tower.out","w",stdout);
n=rd();
int x,y,u,v;
for(R int i=1;i<=n;i++){
xs[i] = po[i].x = rd();
ys[i] = po[i].y = rd();
}
sort(xs+1,xs+1+n);
sort(ys+1,ys+1+n);
totx=unique(xs+1,xs+1+n)-xs-1;
toty=unique(ys+1,ys+1+n)-ys-1;
for(R int i=1;i<=totx;i++){
for(R int j=1;j<=toty;j++){
x=xs[i];y=ys[j];v=id(i,j);
for(R int k=1;k<=n;k++){
ans[v].push_back(dis(x,y,po[k].x,po[k].y));
}
sort(ans[v].begin(),ans[v].end());
}
}
for(R int k=1;k<=n;k++){
for(R int i=1;i<=totx;i++){
for(R int j=1;j<=toty;j++){
sum[i][j][k]=sum[i][j][k-1]+ans[id(i,j)][k-1];
}
}
}
for(R int k=1;k<=n;k++){
int mn=1<<30;
for(R int i=1;i<=totx;i++){
for(R int j=1;j<=toty;j++){
mn=min(mn,sum[i][j][k]);
}
}
printf("%d
",mn);
}
return 0;
}