2017.7.3 校内赛 【模拟】 【贪心】 【??】

暑假开始了,竞赛生活也开始了。
今天进行了校内赛。
先来一个样例解释

这里写图片描述
好萌啊!

第一题

这里写图片描述

【解题报告】

直接模拟相应数据结构,判断弹出元素是否和给定数字一致。注意可能会出现不合法的输入,需要特判弹出操作比插入操作多的情况。

代码

#include<cstdio>
#include<cstring>
#include<stack>
#include<queue>
#include<algorithm>
using namespace std;
const int N=1000;
int n,flag[5],opt,v,a,b,c,temp1,temp2;
stack<int> s;
queue<int> q;
priority_queue<int> heap;
int main()
{
    freopen("qu.in","r",stdin);
    freopen("qu.out","w",stdout);
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%d%d",&opt,&v);
        if (opt==1)
        {
            temp1++;
            s.push(v);
            q.push(v);
            heap.push(v);
        }
        if (opt==2)
        {
            temp2++;
            if (s.empty()) flag[1]=1;
            if (q.empty()) flag[2]=1;
            if (heap.empty()) flag[3]=1;
            if (!flag[1]) {a=s.top();s.pop();if(a!=v)flag[1]=1;}
            if (!flag[2]) {b=q.front();q.pop();if(b!=v)flag[2]=1;}
            if (!flag[3]) {c=heap.top();heap.pop();if(c!=v)flag[3]=1;}
        }
    }
    if (temp1>=temp2)
    {
        for (int i=1;i<=3;i++)
        if (!flag[i]) printf("YES\n");
        else printf("No\n");
    }
    else printf("No\nNo\nNo\n");
    return 0;
}

第二题

这里写图片描述

【解题报告】

考虑序列中只有两个元素的情况,此时两种可能多的排列对应答案分别为

max(t1−d1,t1+t2−d2)max(t1−d1,t1+t2−d2)

,和

max(t2−d2,t2+t1−d1)max(t2−d2,t2+t1−d1)

,我们希望选取其中的最小值。注意到t1−d1

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
const int N=1e5+5;
int n;
long long ans,maxn=0,now=0;
int max(long long x,long long y)
{
    if (x>=y) return x;
    else return y;
}
struct event
{
    long long num,tim,final,pre;
}plan[N];
bool cmp(event a,event b)
{
    return a.final<b.final;
}
int main()
{
    freopen("ming.in","r",stdin);
    freopen("ming.out","w",stdout);
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        long long a,b;
        plan[i].num=i;
        scanf("%I64d%I64d",&a,&b);
        plan[i].tim=a,plan[i].final=b;
        plan[i].pre=b-a;
    }
    sort(plan+1,plan+n+1,cmp);
    for (int i=1;i<=n;i++)
    {
        now+=plan[i].tim;
        ans=max(0,now-plan[i].final);
        if (ans>=maxn) maxn=ans;
    }
    printf("%I64d\n",maxn);
    return 0;
}

第三题

这里写图片描述

【解题报告】
每一棵树都由先前的两棵树构造而来,于是可以进行递推。
所求F(Ti)F(Ti)就是TiTi中每一对点的距离和,有

F(Ti)=F(Tai)+F(Tbi)+|Tbi|∑u∈Taid(u,ci)+|Tai|∑u∈Tbid(u,di)+|Tai||Tbi|li.F(Ti)=F(Tai)+F(Tbi)+|Tbi|∑u∈Taid(u,ci)+|Tai|∑u∈Tbid(u,di)+|Tai||Tbi|li.

设A(Ti,u)A(Ti,u)表示TiTi中所有点到uu的距离和,D(Ti,u,v)D(Ti,u,v)表示TiTi中uu到vv的距离,则

F(Ti)=F(Tai)+F(Tbi)+|Tbi|A(Tai,ci)+|Tai|A(Tbi,di)+|Tai||Tbi|li.F(Ti)=F(Tai)+F(Tbi)+|Tbi|A(Tai,ci)+|Tai|A(Tbi,di)+|Tai||Tbi|li.

不失一般,设u∈Taiu∈Tai,

A(Ti,u)=A(Tai,u)+A(Tbi,di)+|Tbi|(li+D(Tai,ci,u)).A(Ti,u)=A(Tai,u)+A(Tbi,di)+|Tbi|(li+D(Tai,ci,u)).

设u,v∈Taiu,v∈Tai,

D(Ti,u,v)=D(Tai,u,v).D(Ti,u,v)=D(Tai,u,v).

设u∈Tai,v∈Tbiu∈Tai,v∈Tbi,则

D(Ti,u,v)=D(Tai,u,ci)+li+D(Tbi,di,v.)D(Ti,u,v)=D(Tai,u,ci)+li+D(Tbi,di,v.)

可以发现递推式参数中的uu、vv都必然是某一个cici或didi,共2m2m个,所以A(Ti,u)A(Ti,u)的参数最多有2m22m2个取值,D(Ti,u,v)D(Ti,u,v)的参数最多有4m34m3个取值。记忆化递推解决。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>
#include<map>
using namespace std;
const int  N=1010;
const int mod=1000000007;
long long m,f[N],siz[N],a[N],b[N],c[N],d[N],l[N];
map<pair<long long,long long>,long long>mp;
long long dis(long long x,long long s,long long t)
{
    if(x==0) return 0;
    long long k=siz[a[x]];
    if(s>=k&&t>=k) return dis(b[x],s-k,t-k);
    else if(s<k&&t<k) return dis(a[x],s,t);
    else if(s>=k) return dis(b[x],s-k,d[x])+dis(a[x],t,c[x])+l[x];
    else return dis(b[x],t-k,d[x])+dis(a[x],s,c[x])+l[x];
}
long long dfs(long long x,long long pos)//x 树编号,pos点编号 
{
    if(x==0) return 0;
    if(mp[make_pair(x,pos)]) return mp[make_pair(x,pos)];
    if(pos>=siz[a[x]]) 
        return mp[make_pair(x,pos)]=dfs(b[x],pos-siz[a[x]])+dfs(a[x],c[x])+siz[a[x]]*(l[x]+dis(b[x],pos-siz[a[x]],d[x]));
    else return mp[make_pair(x,pos)]=dfs(a[x],pos)+dfs(b[x],d[x])+siz[b[x]]*(l[x]+dis(a[x],pos,c[x]));
}
int main()
{
    freopen("zi.in","r",stdin);
    freopen("zi.out","w",stdout);
    scanf("%I64d",&m);
    siz[0]=1;f[0]=0;
    for(long long i=1;i<=m;++i)
    {
        scanf("%I64d%I64d%I64d%I64d%I64d",&a[i],&b[i],&c[i],&d[i],&l[i]);
        f[i]=(f[a[i]]+f[b[i]])%mod;
        long long part1=(siz[a[i]]%mod*siz[b[i]]%mod)%mod;
        part1=(part1%mod*l[i]%mod)%mod;
        f[i]=(f[i]%mod+part1%mod)%mod;
        siz[i]=(siz[a[i]]+siz[b[i]]);
        long long a1=dfs(a[i],c[i])%mod,a2=dfs(b[i],d[i])%mod; 
        a1=(a1*siz[b[i]]%mod)%mod;
        a2=(a2*siz[a[i]]%mod)%mod;
        f[i]=(f[i]%mod+a1%mod+a2%mod)%mod;
    }
    for(long long i=1;i<=m;++i)
    printf("%I64d\n",f[i]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值