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
(未完)