[TOYOTA 2023 Spring Final A] Area Sum 题解
为了便于解题,先考虑一个子矩阵中数的和如何
令
接着枚举目标的子矩阵的长和宽,如果存在长宽给定且满足和为
但是时间复杂度
有一种便捷好想的优化:在每次二分之前(不管是内层的还是外层的),判断一下可能的子矩阵是否在二分的范围内,如果不在范围内,就进行下一次二分。
这样可以将常数大大减小,最终可以控制在
放代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
main(){
ios::sync_with_stdio(false);
int n,m,v,c=0; cin>>n>>m>>v;
function<int(int,int,int,int)> f=[&](int a,int b,int c,int d){
return (c-a+1)*(d*(d+1)-b*(b-1)>>1)+m*(d-b+1)*(c*(c-1)-(a-1)*(a-2)>>1);
}; // 快速计算子矩阵和
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
int xl=1,xr=n-i+1;
if(f(1,i,1,j)<=v&&v<=f(xr,n,m-j+1,m)){ // 优化,内层同理
bool b=false;
do{
int xm=xl+xr>>1,yl=1,yr=m-j+1;
int l=f(xm,1,xm+i-1,j),r=f(xm,yr,xm+i-1,yr+j-1);
if(l<=v&&v<=r){
do{
int ym=yl+yr>>1;
int s=f(xm,ym,xm+i-1,ym+j-1);
if(s==v)b=true; // 找到解
if(s>v)yr=ym-1;
else yl=ym+1;
}while(yl<=yr&&!b);
}
if(l>v)xr=xm-1;
else xl=xm+1;
}while(xl<=xr&&!b); // 外层二分
if(b)c++;
}
}
cout<<c<<endl;
return 0;
}