hdu6514Monitor
theme:给定n*m矩阵,有p个操作:将以(x1,y1),(x2,y2)为左上、右下的矩阵覆盖。之后q次询问:以(x1,y1),(x2,y2)为左上、右下的矩阵是否有全被覆盖?
solution:二维前缀和。先由一次前缀和(差分)计算出每个格子被覆盖的次数之和。然后将不为0的值 置为1,再进行前缀和就算出每个矩阵区域覆盖总数,与矩阵大小比较即可。
#include<bits/stdc++.h>
using namespace std;
#define far(i,t,n) for(int i=t;i<n;++i)
typedef long long ll;
typedef unsigned long long ull;
int a[10000010];
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
memset(a,0,sizeof(a));
int p;
scanf("%d",&p);
far(i,0,p)
{
int x1,y1,x2,y2,b,c,d,e;
scanf("%d%d%d%d",&b,&c,&d,&e);
x1=n-d;
y1=c-1;
x2=n-b;
y2=e-1;
//差分
a[x1*m+y1]+=1;
if(y2+1<m)
a[x1*m+y2+1]-=1;
if(x2+1<n)
a[(x2+1)*m+y1]-=1;
if(y2+1<m&&x2+1<n)
a[(x2+1)*m+y2+1]+=1;
}
//前缀和求出每个小矩阵被覆盖次数
far(i,0,n)
far(j,0,m)
{
if(j-1>=0)
a[i*m+j]+=a[i*m+j-1];
if(i-1>=0)
a[i*m+j]+=a[(i-1)*m+j];
if(i-1>=0&&j-1>=0)
a[i*m+j]-=a[(i-1)*m+j-1];
}
far(i,0,m*n)
{
if(a[i])
a[i]=1;
}
//前缀和,求区间矩阵被覆盖总次数
far(i,0,n)
far(j,0,m)
{
if(j-1>=0)
a[i*m+j]+=a[i*m+j-1];
if(i-1>=0)
a[i*m+j]+=a[(i-1)*m+j];
if(i-1>=0&&j-1>=0)
a[i*m+j]-=a[(i-1)*m+j-1];
}
int q;
scanf("%d",&q);
far(i,0,q)
{
int x1,y1,x2,y2,b,c,d,e;
scanf("%d%d%d%d",&b,&c,&d,&e);
x1=n-d;
y1=c-1;
x2=n-b;
y2=e-1;
int ans=a[x2*m+y2];
if(y1-1>=0)
ans-=a[x2*m+y1-1];
if(x1-1>=0)
ans-=a[(x1-1)*m+y2];
if(x1-1>=0&&y1-1>=0)
ans+=a[(x1-1)*m+y1-1];
if(ans==(x2-x1+1)*(y2-y1+1))
printf("YES\n");
else
printf("NO\n");
}
}
}
/*
6 6
3
2 2 4 4
3 3 5 6
5 1 6 2
2
3 2 5 4
1 5 6 5
*/
**hdu6512Triangle
theme:判断n个数中可否存在构成三角形的三个数。1<=n<=5*10^6,数值在int范围内
solution:对于n个数找构成三角形的三个数的题,按数据范围有不同解法。想法是将这n个数从小到大排序,(下标从0开始),之后从i=1开始,将i,i+1作为三角形较大的两边,判断它们的差(正值)d是否<a[i-1]即可,因为一旦<则满足条件,一旦>,则d更>i-1之前的数了(要使c-b<a,则找到c-b最小值和a最大值,由于c-b最小处可能取多个,所以我们就遍历每一个c-b即可,这样c-b最小即为每个相邻数之差)。这样做时间复杂度就是排序的时间o(nlog(n)),但该题n较大,又存在多组测试数据,o(nlog(n))关闭流同步才1994ms险过,所以考虑进一步优化:
由上述思路转化为两边之和大于第三边的话,相邻两数a[i],a[i+1]之和要是<a[i+2]也一定小于它后面的数,所以遍历时,极端情况就是1,2,3,5,8,13、、、刚好=情况,由斐波那契数列算出n到50左一点就超int了,所以可看n>=50时一定存在三个数(排序后)组成三角形。
#include <cstdio>
#include <list>
#include<iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
int a[5000010];
ll fib[200];
int main()
{
ios::sync_with_stdio(false);
// fib[0]=1,fib[1]=1;
// for(int i=2;i<=100;++i)
// fib[i]=fib[i-1]+fib[i-2];
// cout<<fib[50];
int n;
while(cin>>n)
{
for(int i=0;i<n;++i)
cin>>a[i];
if(n<2)
{
cout<<"NO\n";
continue;
}
if(n>=50)
{
cout<<"YES\n";
continue;
}
sort(a,a+n);
int flag=0;
for(int i=1;i<n-1;++i)
{
int b=a[i+1]-a[i];
if(b<a[i-1])
{
flag=1;
break;
}
}
if(flag)
cout<<"YES\n";
else
cout<<"NO\n";
}
return 0;
}
*hdu6518Clumsy Keke
theme:由矩阵形式给定三视图,一小格代表体积为1.问满足该三视图的图形的最大体积为多少?
solution:题目输入并不是直接按主视图、左视图、俯视图角度给的,所以先确定一下x,y,z轴方向。想象一个由x*y*z的格子堆成的正方体。对于每一视图,如主视图,该格上有图形,则表示它及它后面的格子都可能放小正方体。这样由三个视图的&关系可以确定哪些格子上是可以放小正方体的。
#include <cstdio>
#include <list>
#include <cstring>
#include<iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
int Front[110][110];
int Left[110][110];
int Top[110][110];
int ans[110][110][110];
int main()
{
int mx,my,mz;
while(~scanf("%d%d%d",&mx,&my,&mz))
{
for(int i=0;i<mx;++i)
for(int j=0;j<my;++j)
scanf("%d",&Front[i][j]);
for(int i=0;i<my;++i)
for(int j=0;j<mz;++j)
scanf("%d",&Left[i][j]);
for(int i=0;i<mz;++i)
for(int j=0;j<mx;++j)
scanf("%d",&Top[i][j]);
for(int i=0;i<mx;++i)
for(int j=0;j<my;++j)
for(int z=0;z<mz;++z)
ans[i][j][z]=Front[i][j];
for(int j=0;j<my;++j)
for(int z=0;z<mz;++z)
for(int i=0;i<mx;++i)
ans[i][j][z]&=Left[j][z];
for(int z=0;z<mz;++z)
for(int i=0;i<mx;++i)
for(int j=0;j<my;++j)
ans[i][j][z]&=Top[z][i];
int res=0;
for(int i=0;i<mx;++i)
for(int j=0;j<my;++j)
for(int z=0;z<mz;++z)
res+=ans[i][j][z];
printf("%d\n",res);
}
}