【NOIP模拟赛】a

【NOIP模拟赛】a_第1张图片
题解:
一看值就只有1/0两种那么就可以把求个数转换为求和;
首先很容易想到先预处理从(0,0)到(i,j)的所有矩阵值,然后枚举左上端点,求出新的矩阵,满足条件就加加,但是呢复杂度是O(nnm*m)的显然过不了,那么我们再观察发现给定上端点和小端点时,矩阵从左到右具有单调不减性,那么我们就在每一个上端点和下端点中预处理dp(就是从左上是(i,0)左下是(j,0)的矩阵),然后再枚举右端点然后呢二分查找左端点的最大和最小,ans+=差值;

#include
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>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

你可能感兴趣的:(提高组)