题意:
给你一个(n*n)的矩阵A,其中有(T)个元素不为零。定义矩阵内元素((x,y))的能量值
(E[x][y]=sum_{i=1}^{x}sum_{j=1}^{y}[A[i][j]>0])
有(m)个询问((x,y,d)),每次询问是否存在二元组((x',y'))满足 (x'=x) 或 (y'=y) ,使得
(E[x'][y']*A[x'][y']>=d)
如果存在,则(ans1++,ans2+=min(E[x'][y']))。否则将 (A[x][y]) 修改为零。最后输出(ans1)和(ans2)。
题解:
暴力出奇迹!
我们注意到这道题的时限是5秒,并且还开O2,因此我们只需要打一个优雅的暴力然后卡一波常数即可通过此题。
我们对每一行和每一列都开一个树状数组,维护第(i)行(列)前j个数中,不为零的元素个数。对于每一个询问,我们暴力枚举每一个可行元素,用树状数组查询其能量值,求出符合条件的最小能量值。对于修改,我们只需要修改两个树状数组即可。时间复杂度(O(mnlogn))
代码如下:
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=1000+50,M=1000000+50;
int n,T,m,a[N][N],R[N][N],C[N][N];
LL d[M];
inline int read(){
int x=0,f=1;char ch;
for(ch=getchar();!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-'0';
return x*f;
}
inline int lowbit(int x){
return x&(-x);
}
inline void Add(int F[],int x,int val){
for(;x<=n;x+=lowbit(x))F[x]+=val;
}
inline int Query(int F[],int x){
int ans=0;
for(;x;x-=lowbit(x))ans+=F[x];
return ans;
}
int main(){
n=read(),T=read();
for(register int i=1;i<=T;++i){
int x=read(),y=read(),w=read();
a[x][y]=w;
Add(R[x],y,1);Add(C[y],x,1);
}
m=read();
for(register int i=1;i<=m;++i)d[i]=1LL*read();
int ans1=0;LL ans2=0;
for(register int i=1;i<=m;++i){
int x=read(),y=read();
int flag=0,mincost=1e9;
for(register int j=1,cost=0;j<=n;++j){
cost+=Query(R[j],y);
if(a[j][y] && 1LL*cost*a[j][y]>=d[i]){
flag=1;mincost=cost;break;
}
}
for(register int j=1,cost=0;j<=n;++j){
cost+=Query(C[j],x);
if(a[x][j] && 1LL*cost*a[x][j]>=d[i]){
flag=1;mincost=min(mincost,cost);break;
}
}
if(flag)++ans1,ans2+=1LL*mincost;
else{
if(a[x][y]){
a[x][y]=0;
Add(R[x],y,-1);Add(C[y],x,-1);
}
}
}
printf("%d
%lld
",ans1,ans2);
return 0;
}