题目大意:
题目链接:http://10.156.31.134/contestnew.aspx?cid=128
求一个的矩阵中选出小矩形的方案数,其中一部分格子不可以选。两个矩形不同定义为两个矩形大小不同或位置不同。
思路:
考虑使用容斥,答案即为总方案数减去选择了若干不可以选的格子的方案数。
总方案数非常简单,枚举矩形的右下端点,显然位于该点左上方的任意点均可与该点组成一个矩形。所以对于点一共有中选法。
所以总方案数即为。
那么考虑选择若干坏点的方案数。依然枚举一个右下端点,那么一个坏点可以对这个点产生贡献的充分条件即为该坏点位于端点的左上方。
同时,如果两个坏点均满足上述条件,但是有且,那么显然被完全包含住了,所以依然不可以对这个点产生贡献。
所以我们发现满足条件的坏点在横坐标单调递增的前提下一定满足纵坐标是单调递减的,否则必然存在产生不了贡献的点。
所以对于每一列维护一下能产生贡献的点集,利用求解即可。
代码:
#include <stack>
#include <cstdio>
using namespace std;
typedef long long ll;
const int N=1010;
ll maxn,sum,last[N][N],f[N][N];
int n,a[N][N];
stack<ll> s[N];
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
scanf("%1d",&a[i][j]);
for (int i=1;i<=n;i++)
s[i].push(0);
for (ll i=1;i<=n;i++)
for (ll j=1;j<=n;j++)
{
if (a[i][j]) last[i][j]=j;
else last[i][j]=last[i][j-1];
while (s[j].size()>1 && last[s[j].top()][j]<last[i][j]) s[j].pop();
maxn+=i*j;
f[i][j]=f[s[j].top()][j]+(i-s[j].top())*last[i][j];
sum+=f[i][j];
s[j].push(i);
}
printf("%lld
",maxn-sum);
return 0;
}