P7410
题目传送门
芜湖~
起飞~
Subtask 1-4
设
接下来直接枚举其中的点判断此举这是否合法即可。
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
{
if(a[i][j]<100) continue;
for(int ii=i; ii<=n; ii++)
for(int jj=j; jj<=n; jj++)
{
pan1=0,pan2=0;
for(int l=i; l<=ii; l++)
{
if(pan2) break;
for(int r=j; r<=jj; r++)
{
if(a[l][r]==100) pan1=1;
if(a[l][r]<100) pan2=1;
if(pan2==1) break;
}
}
if(pan1&&!pan2) ans++;
}
Subtask1-8
首先将所有绿度值大于等于
那么怎么求出由多个小正方向形组成的不规则图形的子矩阵个数便是我们当前要解决的问题了。
具体思路如下:
首先把上面数据转化位由
0 1 0
1 1 1
0 1 1
我们可以从
怎么处理与右下方小正方形形成的矩阵数呢?
我的方法比较
从左向右枚举,直到没有
就这样一个一个枚答案就出来。
void dt(int xx,int yy,int maxx)
{
int maxn;
if(!a[xx][yy]) return;
for(int i=yy;i<=maxx;i++)
if(!a[xx][i])break;
else ans++,maxn=i;
dt(xx+1,yy,maxn);
}
int main()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) dt(i,j,n);
swap(ans,ans2);
for(int i=1;i<=num;i++)
a[la[i].x][la[i].y]=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) dt(i,j,n);
cout<<ans2-ans<<endl;
return 0;
}
Subtask 1-10
上面的代码复杂度应该是
030
122
011
这时只需要从左向右枚举一排只可,不再需要向下枚举列了。但是要保证每次想右枚举时,本列列长不能大于最小列长。
#include<iostream>
#include<cstdio>
#define N 510
using namespace std;
int a[N][N]; //处理之前
int n,num
int val[N][N];//处理后的数组
long long ans2,ans;;
struct bala{int x,y;} la[N*N]; //存储等于100的点
void dt(int xx,int yy) //枚举当前点可形成的矩阵数
{
int minn=val[xx][yy]; //minn是最小列长
for(int i=yy;i<=n;i++)
if(!a[xx][i]) break;
else {
minn=min(minn,val[xx][i]);
ans+=minn;
}
}
void prt() //预处理
{
for(int j=1;j<=n;j++)
for(int i=n;i>=1;i--) {
val[i][j]=0; //因为用了两遍所以在这里需要清空
if(a[i][j]) val[i][j]=val[i+1][j]+1;
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
scanf("%d",&a[i][j]);
if(a[i][j]==100)
la[++num].x=i,la[num].y=j;
if(a[i][j]>=100) a[i][j]=1;
else a[i][j]=0;
}
prt();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) dt(i,j,n);
swap(ans2,ans);
for(int i=1;i<=num;i++)
a[la[i].x][la[i].y]=0;
prt();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) dt(i,j,n);
cout<<ans2-ans<<endl;
return 0;
}
来到你谷的第一篇题解,望过!
码风较丑勿喷