1004 Monitor(二维前缀和)
#include<bits/stdc++.h>
using namespace std;
#define debug puts("YES");
#define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define ll long long
#define lrt int l,int r,int rt
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define root l,r,rt
#define mst(a,b) memset((a),(b),sizeof(a))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
const int mod=1e9+7;
const int maxn=1e7+100;
const int ub=1e6;
ll powmod(ll x,ll y){ll t; for(t=1;y;y>>=1,x=x*x%mod) if(y&1) t=t*x%mod; return t;}
ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
/*
题目大意:
给定一个二维平面范围,
和p个监视区,q个偷盗区,
监视区和偷盗区形状是矩形,
q个询问问偷盗区是否被监控去完全覆盖.
题目分析:
二维差分,蛮套路的,
如果知道一维的情况那么二维不难,
比如(x,y),(p,q)给定这两个坐标点,
那么我们要想让这个矩形区域全置1,
把(x,y),(p+1,q+1)打上1的标记,
(x,q+1),(p+1,y)打上-1的标记,
然后做二维前缀和即可,
为了方便统计查询,再做一次前缀和,
查询时判断个数关系即可.
*/
int n,m,pp,qq;
ll a[maxn];
int s(int x,int y){
return x*m+y-1;
}
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
rep(i,0,n+1) rep(j,0,m+1) a[s(i,j)]=0;
scanf("%d",&pp);
rep(i,0,pp){
int x,y,p,q;
scanf("%d%d%d%d",&x,&y,&p,&q);
a[s(x,y)]++,a[s(p+1,q+1)]++;
a[s(x,q+1)]--,a[s(p+1,y)]--;
}
rep(i,1,n+1) rep(j,1,m+1) a[s(i,j)]+=a[s(i-1,j)]+a[s(i,j-1)]-a[s(i-1,j-1)];
rep(i,1,n+1) rep(j,1,m+1) a[s(i,j)]=min(a[s(i,j)],1LL);
rep(i,1,n+1) rep(j,1,m+1) a[s(i,j)]+=a[s(i-1,j)]+a[s(i,j-1)]-a[s(i-1,j-1)];
scanf("%d",&qq);
rep(i,0,qq){
int x,y,p,q;
scanf("%d%d%d%d",&x,&y,&p,&q);
if((1LL*(p-x+1)*(q-y+1))==(a[s(p,q)]-a[s(p,y-1)]-a[s(x-1,q)]+a[s(x-1,y-1)]))
puts("YES");
else puts("NO");
}
}
return 0;
}
1008 模拟
#include<bits/stdc++.h>
using namespace std;
#define debug puts("YES");
#define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define ll long long
#define lrt int l,int r,int rt
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int maxm=1e3+5;
int n,m,k;
int a[maxm][maxm],b[maxm][maxm],c[maxm][maxm];
int main(){
while(scanf("%d%d%d",&n,&m,&k)!=EOF){
int ans=0;
rep(i,0,n) rep(j,0,m) scanf("%d",&a[i][j]);
rep(i,0,m) rep(j,0,k) scanf("%d",&b[i][j]);
rep(i,0,k) rep(j,0,n){
scanf("%d",&c[i][j]);
if(c[i][j]){
rep(p,0,m) if(a[j][p]&&b[p][i]) ans++;
}
}
printf("%d\n",ans);
}
return 0;
}
1009 模拟
#include<bits/stdc++.h>
using namespace std;
#define debug puts("YES");
#define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define ll long long
const int maxn=103;
int nn,mm,kk;
char s[maxn][maxn],ans[maxn*15][maxn*15];
int main(){
while(scanf("%d%d%d",&nn,&mm,&kk)!=EOF){
rep(i,0,nn) scanf("%s",s[i]);
rep(i,0,nn) rep(j,0,mm){
for(int p=i*kk;p<i*kk+kk;p++) for(int q=j*kk;q<j*kk+kk;q++){
ans[p][q]=s[i][j];
}
}
rep(i,0,nn*kk){
rep(j,0,mm*kk) printf("%c",ans[i][j]);
puts("");
}
}
return 0;
}
1011 线段树+思维+二分
#include<bits/stdc++.h>
using namespace std;
#define debug puts("YES");
#define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define ll long long
#define lrt int l,int r,int rt
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define root l,r,rt
#define mst(a,b) memset((a),(b),sizeof(a))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
const int mod=1e9+7;
const int maxn=5e5+10;
const int ub=1e6;
const int INF=-1e9;
ll powmod(ll x,ll y){ll t; for(t=1;y;y>>=1,x=x*x%mod) if(y&1) t=t*x%mod; return t;}
ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
/*
题目大意:
给定n和m个操作,
n代表序列长度,
每个操作给定一个区间,
代表把这个区间的人聚到一起,
其区间效率是这个区间中多少对人没有在之前的区间中
已经聚过.
题目分析:
线段树+思维转化,
我们可以对每个人,维护一个
数组代表其最远认识到右边的哪一个人,
比如如果区间1,4操作后,那么1最远可以认识到4,
考虑到相互性,我们只需要对每个人维护一端即可.
初始化每个人对应的就是他自己的位置.
更新不难,但查询有点困难,对于区间中数组值
大于右端点的,没有贡献,而在右端点之内的,产生与右端点之差的贡献,
我们无法通过普通的区间求和去表示这一关系.
考虑其数组值的单调性,不难发现我们定义的数组值始终是不减的,
那么我们就可以二分出最大的权重小于右端点的位置点,
有了这个点后就可以进行传统的区间更新了,
我们维护最大值和一个区间和,
注意懒惰标记的更新不是直接赋值而是直接取max,越大越好,
其他一些细节就是数据范围的问题了.
*/
int rt[maxn],minv[maxn<<2],x,y;
int maxv[maxn<<2],lazy[maxn<<2];
ll sum[maxn<<2];
void build(lrt){
lazy[rt]=0;
if(l==r){
sum[rt]=maxv[rt]=l;
return ;
}
int mid=l+r>>1;
build(lson),build(rson);
maxv[rt]=max(maxv[rt<<1],maxv[rt<<1|1]);
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void pushdown(lrt){
int mid=l+r>>1;
if(lazy[rt]){
lazy[rt<<1]=max(lazy[rt<<1],lazy[rt]);
lazy[rt<<1|1]=max(lazy[rt<<1|1],lazy[rt]);
maxv[rt<<1]=max(maxv[rt<<1],lazy[rt]);
maxv[rt<<1|1]=max(maxv[rt<<1|1],lazy[rt]);
sum[rt<<1]=1LL*(mid-l+1)*maxv[rt<<1];
sum[rt<<1|1]=1LL*(r-mid)*maxv[rt<<1|1];
lazy[rt]=0;
}
}
int getpos(lrt,int p){
pushdown(root);
if(l==r) return maxv[rt];
int mid=l+r>>1;
if(p<=mid) return getpos(lson,p);
else return getpos(rson,p);
}
void update(lrt,int L,int R,int v){
if(L<=l&&r<=R){
maxv[rt]=max(maxv[rt],v);
sum[rt]=1LL*(r-l+1)*maxv[rt];
lazy[rt]=max(lazy[rt],v);
return;
}
pushdown(l,r,rt);
int mid=l+r>>1;
if(L<=mid) update(lson,L,R,v);
if(mid<R) update(rson,L,R,v);
maxv[rt]=max(maxv[rt<<1],maxv[rt<<1|1]);
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
ll getsum(lrt,int L,int R){
if(L<=l&&r<=R) return sum[rt];
pushdown(l,r,rt);
int mid=l+r>>1;
ll ans=0;
if(L<=mid) ans+=getsum(lson,L,R);
if(mid<R) ans+=getsum(rson,L,R);
maxv[rt]=max(maxv[rt<<1],maxv[rt<<1|1]);
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
return ans;
}
int n,m;
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
build(1,n,1);
rep(i,0,m){
scanf("%d%d",&x,&y);
int l=1,r=n,p=0;
while(l<=r){
int mid=l+r>>1;
if(getpos(1,n,1,mid)<y){
p=mid;l=mid+1;
}else{
r=mid-1;
}
}
p=min(p,y);
if(x<=p){
printf("%lld\n",1LL*(p-x+1)*y-getsum(1,n,1,x,p));
update(1,n,1,x,p,y);
}else{
puts("0");
}
}
}
return 0;
}
1003 Reverse It(组合数学+消去重复度)
#include<bits/stdc++.h>
using namespace std;
#define debug puts("YES");
#define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define ll long long
#define lrt int l,int r,int rt
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define root l,r,rt
#define mst(a,b) memset((a),(b),sizeof(a))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
const int mod=1e9+7;
const int maxn=1e2+100;
const int ub=1e6;
ll powmod(ll x,ll y){ll t; for(t=1;y;y>>=1,x=x*x%mod) if(y&1) t=t*x%mod; return t;}
ll gcd(ll x,ll y){
if(y==0) return x;
return gcd(y,x%y);
}
ll n,m;
char s[maxn][maxn];
ll C(ll x,int y){
if(x<1LL*y) return 0;
ll ans=1,tmp=1;
for(int i=1;i<=y;i++){
ans=ans*(x-i+1);
tmp*=i;
}
return ans/tmp;
}
int main(){
while(scanf("%lld%lld",&n,&m)!=EOF){
rep(i,0,n) scanf("%s",s[i]);
ll ret=C(n+1,2)*C(m+1,2);
ret=C(ret,2)+1;
ret-=4LL*C(n+1,3)*C(m+1,3);///对角
ret-=8LL*C(n+1,3)*C(m+1,3);///斜率
ret-=(2LL*C(n+1,2)*C(m+1,4)+2LL*C(n+1,4)*C(m+1,2));///分割
ret-=(n+m-3)*(C(n+1,2)*C(m+1,2));
printf("%lld\n",ret);
}
return 0;
}