2017.7.3 机房测试(模拟,贪心,图论)

本文解析了使用栈、队列及优先队列等数据结构实现模拟题目的方法,并通过具体实例展示了如何处理输入数据,包括元素的插入和弹出操作。此外还探讨了一种涉及树形结构递归计算的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里写图片描述
【解题报告】
直接模拟相应数据结构,判断弹出元素是否和给定数字一致。注意可能会出现不合法的输入,需要特判弹出操作比插入操作多的情况。

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
using namespace std;
#define N 10010

int n,a[N],b[N];
bool flag[5];
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",&a[i],&b[i]);
        if(a[i]==1) 
        {
            S.push(b[i]);
            q.push(b[i]);
            heap.push(b[i]);
        }
        if(a[i]==2) 
        {
            if(S.empty()) flag[1]=1;
            if(q.empty()) flag[2]=1;
            if(heap.empty()) flag[3]=1;
            if(!flag[1]) {int t1=S.top();S.pop();if(t1!=b[i]) flag[1]=1;}
            if(!flag[2]) {int t2=q.front();q.pop();if (t2!=b[i]) flag[2]=1;}
            if(!flag[3]) {int t3=heap.top();heap.pop();if (t3!=b[i]) flag[3]=1;}
        }
    }
    for(int i=1;i<=3;++i)
    {
        if(!flag[i]) printf("YES\n");
        else printf("No\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<algorithm>
using namespace std;
#define N 100010

int n;
int ans=0;
struct NODE 
{
    int t,d,sum;
    NODE(){sum=0;}
    friend bool operator<(const NODE &a,const NODE &b) 
    {return a.d<b.d||(a.d==b.d&&a.t<b.t);}
}a[N];

int main() 
{
    freopen("ming.in","r",stdin);
    freopen("ming.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%d%d",&a[i].t,&a[i].d);
    sort(a+1,a+n+1);
    a[0].sum=0;
    for(int i=1;i<=n;++i)
    {
        a[i].sum=a[i-1].sum+a[i].t;
        ans=max(ans,max(0,a[i].sum-a[i].d));    
    }
    printf("%d\n",ans);
    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<map>
using namespace std;
#define N 1010
#define mod 1000000007
#define dnt long long

dnt m,f[N],siz[N],a[N],b[N],c[N],d[N],l[N];
map<pair<dnt,dnt>,dnt>mp;

dnt dis(dnt x,dnt s,dnt t)
{
    if(x==0) return 0;
    dnt 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];
}
dnt dfs(dnt x,dnt 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(dnt 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;
        dnt 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]]);
        dnt 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(dnt 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、付费专栏及课程。

余额充值