B.The writing on the wall
题目链接:https://nanti.jisuanke.com/t/30991
题意:给你一个n*m得矩阵,中间有些是黑色,问你里面有多少个没有黑色矩阵得子矩阵
思路:对于一个长为L, 高为H的无黑点矩阵中包含的高为H的子矩阵个数为L+(L-1)+(L-2)+...+1个;这是直接算的一种方法;如何程序表示该计算呢?其中h是固定值
for(int i=1; i<=L; i++){
for(int j=i; j>0; j--){
cnt+=h;
}
}
这样的一个双层循环就表示了上式;那么所有子矩阵个数就是三层循环,高由1->H:
for(int h=1; h<=H; h++){
for(int i=1; i<=L; i++){
for(int j=i; j>0; j--){
cnt+=h;
}
}
}
这是其中没有黑点的;如果在某处加了个黑点又如何计算呢?
我们固定一个右下得点让他往上往左看,如果当前小是不是再往右就更小了呢?
for(int i=1; i<=H; i++){
for(int j=1; j<=L; j++){
h=i;
for(int k=j; k>0; k--){
h=min(h, i-p[k]);
cnt+=h;
}
}
}
//p[k]表示第k列中在i行上边的第一个黑点的位置,
那么我们现在用n代替H,m代替L这样就是一个复杂度为O(n*m*m)得算法,看题后我们应该吧100当作m另一个当作n这样就时间刚好,我们用标记黑点得位置去维护h即可
附上AC代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int a[100010][110],up[110];
int main()
{
int T,cas=1;
scanf("%d",&T);
int n,m,k,x,y;
ll minn;
while(T--){
scanf("%d%d%d",&n,&m,&k);
memset(a,0,sizeof a);
memset(up,0,sizeof up);
for(int i=0;i<k;i++){
scanf("%d%d",&x,&y);
a[x][y]=1;
}
ll ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
if(a[i][j])up[j]=i;
for(int j=1;j<=m;j++){
minn=0x7f7f7f7f7f7f7f7f;
for(int k=j;k>0;k--){
minn=min(minn,(ll)(i-up[k]));
ans+=minn;
}
}
}
printf("Case #%d: %lld\n",cas++,ans);
}
return 0;
}