2019中山大学程序设计竞赛(重现赛)
题意:给你n个木棒,判断其能否组成三角形。
这题就是斐波那契数数列的应用,把斐波那契数列打出来,可以知道第47项就大于2^31-1了,于是的话,最长的不能构成三角形的序列的长度就是46了,若序列长度>=47,那就必有一个长度>=2的区间不满足斐波那契数列,那就可以构成,若序列长度<47就暴力判断。
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e6+10;
#define ll long long
int a[maxn],n,flag;
int main()
{
while(scanf("%d",&n)!=EOF)
{
flag=0;
for(int i=1;i<=n;i++) scanf("%d",&(a[i]));
if(n>=47)
{
flag=1;
}
else
{
sort(a+1,a+n+1);
for(int i=3;i<=n;i++)
if(a[i-2]+a[i-1]>a[i])
{
flag=1;
break;
}
}
puts((flag==1)?"YES":"NO");
}
return 0;
}
题意就是一个n*m的矩阵,p个监控,q个小偷活动区域,对每个活动区域问是否能被监控区域完全覆盖。
二维差分+二维前缀和,二维差分就是假如x1,y1,x2,y2对应区域的值加x,那么直接对差分数组c[x1][y1]+=x, c[x2+1][y2+1]+=x,
c[x2+1][y1]-=x,c[x1][y2+1]-=x,然后再对c数组求一次二维前缀和就可以得到每一个位置的变化值了(可以和一维的类比),顺便学了手开动态二维数组,利用指针开动态二维数组我不会,就用vector开了
#include<bits/stdc++.h>
using namespace std;
int n,m,p,q;
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
vector<int>c[n+10];
for(int i=0;i<=n+5;i++)
for(int j=0;j<=m+5;j++)
c[i].push_back(0);
scanf("%d",&p);
for(int i=1;i<=p;i++)
{
int xo,yo,xt,yt;
scanf("%d%d%d%d",&xo,&yo,&xt,&yt);
c[xo][yo]++,c[xt+1][yt+1]++,c[xt+1][yo]--,c[xo][yt+1]--;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
c[i][j]+=c[i-1][j]+c[i][j-1]-c[i-1][j-1];
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(c[i][j]>=1) c[i][j]=1;
c[i][j]+=c[i-1][j]+c[i][j-1]-c[i-1][j-1];
}
scanf("%d",&q);
while(q--)
{
int xo,yo,xt,yt;
scanf("%d%d%d%d",&xo,&yo,&xt,&yt);
if((c[xt][yt]-c[xt][yo-1]-c[xo-1][yt]+c[xo-1][yo-1])==((xt-xo+1)*(yt-yo+1)))
printf("YES\n");
else
printf("NO\n");
}
}
return 0;
}
http://acm.hdu.edu.cn/showproblem.php?pid=6521
Party
有n个人,然后有m个派对,问你每个派对上有多少对人是新认识的。
推荐一篇大佬的博客,讲的很清楚 https://blog.csdn.net/u013534123/article/details/89409912
我是在其基础上优化了一些,定义一个R[]数组,表示的是每个人认识的最右边的人,然后因为区间是连续的,所以R[]数组是非严格单调递增的,对于一个区间l到r,新认识的人的对数就是r*(pos-l+1)-sum(R[i],l<=i<=pos),这里pos表示的是满足R[i]<=r的最大的pos,pos位置可以用线段树维护。感觉每次写线段树,找bug都能找一天qwq。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ls rt<<1
#define rs rt<<1|1
const int maxn=5e5+10;
struct node
{
int maxx,l,r,lazy;
ll sum;
node(ll sum=0LL,int maxx=0,int l=0,int r=0,int lazy=0)
{
this->sum=sum;
this->maxx=maxx;
this->l=l;
this->r=r;
this->lazy=lazy;
}
}tree[maxn<<2];//tree维护的是r数组
void pushup(int rt)
{
tree[rt].sum=tree[ls].sum+tree[rs].sum;
tree[rt].maxx=max(tree[ls].maxx,tree[rs].maxx);
}
void pushdown(int rt)
{
if(tree[rt].lazy)
{
tree[ls].lazy=tree[rs].lazy=tree[rt].lazy;
tree[ls].sum=1LL*(tree[ls].r-tree[ls].l+1)*tree[ls].lazy;
tree[rs].sum=1LL*(tree[rs].r-tree[rs].l+1)*tree[rs].lazy;
tree[ls].maxx=tree[rs].maxx=tree[rt].lazy;
tree[rt].lazy=0;
}
}
void build(int rt,int l,int r)
{
tree[rt].l=l,tree[rt].r=r;
tree[rt].lazy=0;
if(l==r)
{
tree[rt].sum=tree[rt].maxx=l;
return ;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(rt);
}
int querypos(int rt,int x)
{
if(tree[rt].l==tree[rt].r)
{
if(tree[rt].maxx<=x)
return tree[rt].l;
else
return -1;
}
pushdown(rt);
if(tree[ls].maxx<=x)
return max(tree[ls].r,querypos(rs,x));
else
return querypos(ls,x);
}
ll querysum(int rt,int l,int r)
{
if(tree[rt].l>=l&&tree[rt].r<=r)
return tree[rt].sum;
int mid=(tree[rt].l+tree[rt].r)>>1;
pushdown(rt);
if(mid>=r)
return querysum(ls,l,r);
else
if(mid<l)
return querysum(rs,l,r);
else
return querysum(ls,l,mid)+querysum(rs,mid+1,r);
}
void update(int rt,int l,int r,int val)
{
if(tree[rt].l>=l&&tree[rt].r<=r)
{
tree[rt].lazy=val;
tree[rt].maxx=val;
tree[rt].sum=1LL*(tree[rt].r-tree[rt].l+1)*val;
return ;
}
int mid=(tree[rt].l+tree[rt].r)>>1;
pushdown(rt);
if(mid>=r)
update(ls,l,r,val);
else
if(mid<l)
update(rs,l,r,val);
else
update(ls,l,mid,val),update(rs,mid+1,r,val);
pushup(rt);
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
build(1,1,n);
while(m--)
{
ll ans;
int l,r,pos;
scanf("%d%d",&l,&r);
pos=querypos(1,r);
if(pos<=l-1)
ans=0LL;
else
ans=1LL*r*(pos-l+1)-1LL*querysum(1,l,pos),update(1,l,pos,r);
printf("%lld\n",ans);
}
}
return 0;
}