[2019杭电多校第六场]

1005传送门


题意:一个二维图上有若干个点,每个点有一个坐标值(xi,yi),以及一个价值(vi) ( -1e9<=xi,yi,vi<=1e9),求一个价值和最大的矩形(只需输出最大价值和)
题解:离散化后枚举上下边界可以将二维图降维为一个求一维动态最大字段和的问题,在横轴上建立线段树即可维护最大字段和

#include<bits/stdc++.h>
using namespace std;
#define debug(x) cout<<#x<<" is "<<x<<endl;
typedef long long ll;
const int maxn=2e3+5;
struct pot{
    int x;
    int y;
    ll val;
}p[maxn];
struct node{
    int l;
    int r;
    ll sum;
    ll maxxval;
    ll maxxpre;
    ll maxxnxt;
}nod[maxn<<2];
struct pot2{
    int x;
    ll val;
};
vector<struct pot2>g[maxn];
int xx[maxn],yy[maxn];
void build(int rt,int l,int r){
    nod[rt].l=l;
    nod[rt].r=r;
    nod[rt].sum=nod[rt].maxxnxt=nod[rt].maxxpre=nod[rt].maxxval=0;
    if(l==r){
        return;
    }
    int mid=(l+r)>>1;
    build(rt<<1,l,mid);
    build((rt<<1)|1,mid+1,r);
}
void pushup(int rt){
    nod[rt].maxxpre=max(nod[rt<<1].maxxpre,nod[rt<<1].sum+nod[(rt<<1)|1].maxxpre);
    nod[rt].maxxnxt=max(nod[(rt<<1)|1].maxxnxt,nod[rt<<1].maxxnxt+nod[(rt<<1)|1].sum);
    nod[rt].maxxval=max(max(nod[rt<<1].maxxval,nod[(rt<<1)|1].maxxval),max(max(nod[rt<<1].maxxnxt,nod[(rt<<1)|1].maxxpre),nod[rt<<1].maxxnxt+nod[(rt<<1)|1].maxxpre));
    nod[rt].sum=nod[rt<<1].sum+nod[(rt<<1)|1].sum;
}
void update(int rt,int l,int r,int x,ll val){
    if(l==r){
        nod[rt].sum+=val;
        nod[rt].maxxval+=val;
        nod[rt].maxxnxt+=val;
        nod[rt].maxxpre+=val;
        return ;
    }
    int mid=(l+r)>>1;
    if(mid>=x)update(rt<<1,l,mid,x,val);
    else update((rt<<1)|1,mid+1,r,x,val);
    pushup(rt);
}
ll query(int rt){
    return max(max(nod[rt].maxxval,nod[rt].maxxpre),nod[rt].maxxnxt);
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){g[i].clear();scanf("%d%d%lld",&p[i].x,&p[i].y,&p[i].val);xx[i]=p[i].x,yy[i]=p[i].y;}
        sort(xx+1,xx+1+n);
        sort(yy+1,yy+1+n);
        int siz1=unique(xx+1,xx+1+n)-(xx+1);
        int siz2=unique(yy+1,yy+1+n)-(yy+1);
        for(int i=1;i<=n;i++){
            p[i].x=lower_bound(xx+1,xx+1+siz1,p[i].x)-xx;
            p[i].y=lower_bound(yy+1,yy+1+siz2,p[i].y)-yy;
            struct pot2 aa;
            aa.x=p[i].x;
            aa.val=p[i].val;
            g[p[i].y].push_back(aa);
        }
        ll ans=0;
        for(int i=1;i<=siz2;i++){
            build(1,1,siz1);
            for(int j=i;j<=siz2;j++){
                for(int k=0;k<g[j].size();k++){
                    struct pot2 bb=g[j][k];
                    update(1,1,siz1,bb.x,bb.val);
                }
                ans=max(ans,query(1));
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

1008传送门


题意:定义f(n,m)为大于n的第m个与n互质的数,令k=(f(n,m)-n)^n,现在已知k和m的值,输出最小的满足要求的n或者-1(不存在)(k<=1e18,m<=100)
题解:由于k巨大而m很小,并且由m最大为100可以知道f(n,m)-n一定不太大(打表也可以发现f(n,m)-n始终<210),所以可以直接枚举(f(n,m)-n)的值,并且利用k的二进制下的各个值来计算n,检查枚举出的n的f(n,m)是否满足要求。总复杂度应为O(210 * 2^10)

#include<bits/stdc++.h>
using namespace std;
//#define debug(x) cout<<#x<<" is "<<x<<endl;
typedef long long ll;
ll gcd(ll x,ll y){
    if(y==0)return x;
    return gcd(y,x%y);
}
ll k,m;
bool dfs(ll pos,ll sum1,ll sum2){
    if(pos==0){
        if(gcd(sum1+sum2,sum2)==1){
            int t1=0;
            for(ll i=sum2+1;i<=sum1+sum2;i++){
                if(gcd(i,sum2)==1)t1++;
                if(t1>m)return 0;
            }
            if(t1<m)return 0;
            printf("%lld\n",sum2);
            return 1;
        }
        return 0;
    }
    if((k>>(pos-1))&1){
        if(dfs(pos-1,sum1+(1<<(pos-1)),sum2))return 1;
        return dfs(pos-1,sum1,sum2+(1<<(pos-1)));
    }
    else{
        if(dfs(pos-1,sum1,sum2))return 1;
        return dfs(pos-1,sum1+(1<<(pos-1)),sum2+(1<<(pos-1)));
    }
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%lld%lld",&k,&m);
        ll x=k;
        ll t1=0;
        ll ac=0;
        while(x){
            t1++;
            if(t1>9&&(x%2)){
                ac+=(1ll<<(t1-1));
            }
            x/=2;
        }
        if(dfs(9ll,0ll,ac)){
            ;
        }
        else{
            printf("-1\n");
        }
    }
    return 0;
}

1012传送门


题意:给出一个小顶堆,两人轮流从叶子处取数同时删除取走的叶子,求二者都最优情况下分别得到的总和
题解:大顶堆优先队列

#include<bits/stdc++.h>
using namespace std;
//#define debug(x) cout<<#x<<" is "<<x<<endl;
typedef long long ll;
const int maxn=1e5+5;
priority_queue<ll>pq;
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        ll s1=0;
        ll s2=0;
        for(int i=1;i<=n;i++){ll a;scanf("%lld",&a);pq.push(a);}
        for(int i=1;i<=n;i++){
            ll xx=pq.top();pq.pop();
            if(i%2)s1+=xx;
            else s2+=xx;
        }
        printf("%lld %lld\n",s1,s2);
    }
    return 0;
}
posted @ 2019-08-09 15:56  MekakuCityActor  阅读(404)  评论(0编辑  收藏  举报