题解:
一看值就只有1/0两种那么就可以把求个数转换为求和;
首先很容易想到先预处理从(0,0)到(i,j)的所有矩阵值,然后枚举左上端点,求出新的矩阵,满足条件就加加,但是呢复杂度是O(nnm*m)的显然过不了,那么我们再观察发现给定上端点和小端点时,矩阵从左到右具有单调不减性,那么我们就在每一个上端点和下端点中预处理dp(就是从左上是(i,0)左下是(j,0)的矩阵),然后再枚举右端点然后呢二分查找左端点的最大和最小,ans+=差值;
#include<bits/stdc++.h>
using namespace std;
long long n,m,k,u;
long long l,r,tot;
long long suml[32][50005];
long long sumh[32][50005];
long long mapa[32][50005];
long long dp[50005];
bool flag;
long long read(){
long long num=0;
char ch=getchar();
while(ch>'9'||ch<'0'){
ch=getchar();
}
while(ch>='0'&&ch<='9'){
num=(num<<1)+(num<<3)+ch-'0';
ch=getchar();
}
return num;
}
long long find(int L,int R,int x){
int ans=L;
while (L<R){
int mid=(L+R)>>1;
if(dp[mid]>x) R=mid-1;
else {
ans=max(ans,mid);
L=mid+1;
}
}
while(dp[ans+1]<=x&&(ans+1)<=m) ans++;
return ans;
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%1d",&k);
if((!flag)&&k) flag=1;
sumh[i][j]=k+sumh[i][j-1];
suml[i][j]=k+suml[i-1][j];
mapa[i][j]=suml[i][j]+sumh[i][j]-k+mapa[i-1][j-1];
}
}
l=read(),r=read();
if(l==0&&r==n*m){
printf("%lld",m*(m+1)/2*(n+1)*(n)/2);
return 0;
}
if(!flag){
if(l==0){
printf("%lld",m*(m+1)/2*(n+1)*(n)/2);
return 0;
}
else puts("0");
return 0;
}
for(int i=1;i<=n;i++){
for(int j=0;j<i;j++){
for(int v=1;v<=m;v++){
dp[v]=mapa[i][v]-mapa[j][v];
}
for(k=0;k<m;k++){
int L=lower_bound(dp+k+1,dp+m+1,dp[k]+l)-dp;
if(L!=m+1){
int R=find(L,m,dp[k]+r);
tot+=(R-L+1);
}
}
}
}
printf("%lld",tot);
return 0;
}