2019中山大学程序设计竞赛(重现赛)

18 篇文章 0 订阅
3 篇文章 0 订阅

Triangle

题意:给你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;
}

 

 

Monitor

题意就是一个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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值