【解题报告】
直接模拟相应数据结构,判断弹出元素是否和给定数字一致。注意可能会出现不合法的输入,需要特判弹出操作比插入操作多的情况。
代码如下:
#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;
}