1小时训练7

A - New Year Book Reading

一个人要读n本书,每本书的编号为1~n,每本书有一个重量wi,要读m天,给出每天要读的书的编号,某本书可以多次读。书从上到下堆成一堆,他把每天要读的书抽出来(把上面的搬开,拿出要的的书书,再把上面的放回),再把这本书放回到这摞书的最上面。问根据他的阅读顺序怎样确定书的初始化排列顺序,使他搬书的重量最小,求出这个最小重量。每天搬书的重量不包括他要读的那本书,搬出搬回只算一次。
Input
3 5
1 2 3
1 3 2 3 1
Output
12

思路

考虑在已有的序列中新加入一本书,显然将这本书放在序列的最底部方案最优。当第i天要读的这本书已在序列中时,ans+=这本书前一次出现的位置~当前位置书的总重量。

代码

#include<cstdio>
#define MAXN 500
#define MAXM 1000
int n,m,x;
int ans;
int v[MAXN+5];
int pos[MAXN+5];
int sum[MAXM+5];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&v[i]);
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&x);
        ans+=sum[i-1]-sum[pos[x]];
        if(pos[x]!=0)
        {
            for(int j=pos[x];j<i;j++)
                sum[j]-=v[x];
        }
        sum[i]=sum[i-1]+v[x],pos[x]=i;
    }
    printf("%d\n",ans);
}

B - New Year Domino

给一些多米诺骨牌,可以花费w的代价使某个骨牌的长度加w,询问推倒一段区间[L,R]的骨牌至少要花多少代价(只能推倒骨牌L)。
Input
6
1 5
3 3
4 4
9 2
10 1
12 1
4
1 2
2 4
2 5
2 6
Output
0
1
1
2

思路

离线操作,将L从大到小排序,同时从后向前插入骨牌,直到L为止。
考虑如何插入一个骨牌:
把每个骨牌看作一个点,要求如果一个骨牌倒下,那么它能够压倒的骨牌与它在同一个联通块。
同一个联通块内部,当第一个倒下后,全部都不需要任何代价可以倒下,我们处理询问时,只需要计算不同联通块之间的代价即可。
假设当前要插入骨牌X。用一个盏来储存每个联通块的第一个位置。
设盏中G在X倒下可覆盖的范围内,H不在该范围内。
有Lenmax[X]=max(Lenmax[X],Lenmax[G]),将G加入X的联通块,val[G]的值修改为0,同时弹出G。
因为H不在X倒下的范围内,所以 val[X]=max(0,pos[H]-Lenmax[x])。
询问时要求出val[L]~val[R]的和,可用线段树储存val数组。

代码

#include<cstdio>
#include<stack>
#include<algorithm>
using namespace std;
#define MAXN 200010
#define LL long long
LL ans[MAXN],tree[MAXN*4],p[MAXN],l[MAXN];
int n,m;
struct node
{
    int l,r,id;
}q[MAXN];
stack<int>s;
int fa[MAXN];
int FindSet(int u)
{
    if(fa[u]==0) return u;
    return fa[u]=FindSet(fa[u]);
}
void Add(int l,int r,int id,LL val,int pos,bool f)
{
    if(l==r)
    {
        tree[id]+=val;
        if(f) tree[id]=0;
        return;
    }
    int mid=(l+r)>>1;
    if(pos<=mid) Add(l,mid,id*2,val,pos,f);
    else Add(mid+1,r,id*2+1,val,pos,f);
    tree[id]=tree[id*2]+tree[id*2+1];
}
LL Query(int l,int r,int id,int l1,int r1)
{
    if(l1<=l&&r<=r1) return tree[id];
    int mid=(r+l)/2;
    LL ret=0LL;
    if(l1<=mid) ret+=Query(l,mid,id*2,l1,r1);
    if(r1>mid) ret+=Query(mid+1,r,id*2+1,l1,r1);
    return ret;
}
void Add(int x)
{
    LL maxl=0;
    while(!s.empty()&&p[s.top()]<=l[x])
    {
        maxl=max(maxl,l[s.top()]);
        Add(1,n,1,0,s.top(),1);
        fa[s.top()]=x;
        s.pop();
    }
    l[x]=max(l[x],maxl);
    if(!s.empty()&&p[s.top()]-l[x]>0)
        Add(1,n,1,p[s.top()]-l[x],x,0);
    s.push(x);
}
bool cmp(node a,node b)
{
    if(a.l!=b.l)
        return a.l>b.l;
    return a.r<b.r;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%I64d%I64d",&p[i],&l[i]);
        l[i]+=p[i];
    }
    scanf("%d",&m);
    for(int i=0;i<m;i++)
    {
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].id=i;
    }
    sort(q,q+m,cmp);
    int now=n;
    for(int i=0;i<m;i++)
    {
        while(now>=q[i].l)
            Add(now--);
        if(now<FindSet(q[i].r)-1)
            ans[q[i].id]=Query(1,n,1,now+1,FindSet(q[i].r)-1);
    }
    for(int i=0;i<m;i++)
        printf("%I64d\n",ans[i]);
}

C - New Year Running

(未完)

猜你喜欢

转载自blog.csdn.net/qq_41343943/article/details/79418264