2019 Multi-University Training Contest 6

1005  Snowy Smile

给n个坐标,每个坐标有个权值(可小于零),问如何取矩形使得矩形内的权值和最大。

题解:

首先将纵坐标离散化到 O(n) 的范围内,方便后续的处理。 将所有点按照横坐标排序,枚举矩形的上边界,然后往后依次加入每个点,这样就确定了 矩形的上下边界。设 v[y] 表示矩形内部纵坐标为 y 的点的权值和,则答案为 v 的最大子段和, 用线段树维护带修改的最大子段和即可。 时间复杂度 O(n2logn)。

自从学了线段树的区间合并以来今天是第一次遇到区间合并的题

【代码】

#include
using namespace std;
const int N=2e3+10;
typedef long long ll;
struct node
{
    int x,y;
    ll w;
}a[N];
struct node1
{
    int x;
    ll w;
};
int n;
int X[N],Y[N],tot1,tot2;
vectorG[N];
ll ls[N*4],rs[N*4],mx[N*4],sum[N*4];
void pushup(int id,int l,int r)
{
    ls[id]=max(ls[id<<1],sum[id<<1]+ls[id<<1|1]);
    rs[id]=max(rs[id<<1|1],sum[id<<1|1]+rs[id<<1]);

    sum[id]=sum[id<<1|1]+sum[id<<1];

    mx[id]=max(mx[id<<1],mx[id<<1|1]);
    mx[id]=max(mx[id],rs[id<<1]+ls[id<<1|1]);
    mx[id]=max(mx[id],sum[id<<1|1]+rs[id<<1]);
    mx[id]=max(mx[id],ls[id]);
    mx[id]=max(mx[id],rs[id]);
}
void up(int id,int l,int r,int pos,ll w)
{
    if(l==r)
    {
        sum[id]+=w;
        ls[id]+=w;
        rs[id]+=w;
        mx[id]+=w;
        return ;
    }
    int mid=l+r>>1;
    if(pos<=mid) up(id<<1,l,mid,pos,w);
    else up(id<<1|1,mid+1,r,pos,w);
    pushup(id,l,r);
}
int main()
{
    int _;
    cin>>_;
    while(_--){
        scanf("%d",&n);
        for(int i=1;i<=n;++i) G[i].clear();
        for(int i=1;i<=n;++i)
        {
            scanf("%d%d%lld",&a[i].x,&a[i].y,&a[i].w);
            X[i]=a[i].x,Y[i]=a[i].y;
        }
        sort(X+1,X+1+n);
        sort(Y+1,Y+1+n);
        tot1=unique(X+1,X+1+n)-X-1;
        tot2=unique(Y+1,Y+1+n)-Y-1;
        for(int i=1;i<=n;++i)
        {
            a[i].x=lower_bound(X+1,X+1+tot1,a[i].x)-X;
            a[i].y=lower_bound(Y+1,Y+1+tot2,a[i].y)-Y;
            G[a[i].y].push_back({a[i].x,a[i].w});
        }
        ll ans=0;
        for(int i=1;i<=tot2;++i)//枚举下边界
        {
            for(int j=0;j<=4*tot1;++j)
            ls[j]=rs[j]=mx[j]=sum[j]=0;
            for(int j=i;j>=1;--j)//枚举上边界
            {
                for(node1 v:G[j])//对于这一行有多少个点
                up(1,1,tot1,v.x,v.w);
                ans=max(ans,mx[1]);
            }
        }
        printf("%lld\n",ans);

    }
}

1008 TDL 

签到题

#include
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
const int N=1e5+10;
ll gcd(ll a,ll b)
{
    return b?gcd(b,a%b):a;
}
int main()
{
    int _;
    cin>>_;
    while(_--)
    {
        ll k,m;
        scanf("%lld%lld",&k,&m);
        bool flag=0;
        ll ans=-1;
        for(ll n=max(k-500,1ll);n<=k+500;++n)
        {
            int cnt=0;
            //printf("n:%lld\n",n);
            ll f;
            for(f=n+1;;++f)
            {
                if(gcd(f,n)==1)
                cnt++;
                if(cnt==m) break;
            }
            if(((f-n)^n)==k)
            {
                ans=n;break;
            }
        }
        printf("%lld\n",ans);
    }
}

1012 Stay Real

签到题

#include
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
const int N=1e5+10;
int n,du[N],h[N];
struct node
{
    int id,val;
    bool operator <(const node o)const
    {
        return val>_;
    while(_--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&h[i]);
            if(i>1) du[i/2]++;
        }
        priority_queueque;
        for(int i=1;i<=n;++i)
        {
            if(du[i]==0) que.push({i,h[i]});
        }
        ll ans1=0,ans2=0;//ans 是sunset
        ll f=0;
        while(que.size())
        {
            node now =que.top();que.pop();
            if(!f) ans1+=now.val;
            else ans2+=now.val;
            f=1-f;
            if(now.id==1) break;
            du[now.id/2]--;
            if(now.id/2!=0&&du[now.id/2]==0) que.push({now.id/2,h[now.id/2]});

        }
        printf("%lld %lld\n",ans1,ans2);
    }
}

 

你可能感兴趣的:(2019杭电多校题解)