多校冲刺 NOIP 20211111 模拟 (28)
冲了3个正解,结果一个挂了,哭了。。。。。
T1 嗑瓜子
水笔期望dp,不多阐述
T2 第 k 大查询
由于k<=50所以考虑找到这个数字前面第k个比它大的,和后面的数字进行区间匹配,
顺序删点保证里面的数字都是比当前数字大的,然后链表维护就行了
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int maxn=5e5+5;
int nxt[maxn],lst[maxn],n,a[maxn],bel[maxn],k;ll ans=0;
signed main()
{
freopen("kth.in","r",stdin);
freopen("kth.out","w",stdout);
n=read(); k=read(); nxt[0]=1;
for(int i=1;i<=n;i++) a[i]=read(),bel[a[i]]=i;
for(int i=1;i<=n+1;i++) lst[i]=i-1,nxt[i]=i+1;
for(int i=1;i<=n;i++)
{
int x=bel[i]; int cnt=0,from=x,to=x;
if(n-i+1<k) break;
while(from&&cnt<k) {cnt++;from=lst[from];}
while(cnt<k) {to=nxt[to];cnt++;}
while(from!=x&&to<=n)
{
ans=ans+1ll*(nxt[from]-from)*(nxt[to]-to)*i;
from=nxt[from];to=nxt[to];
}
nxt[lst[x]]=nxt[x]; lst[nxt[x]]=lst[x];
}
printf("%lld\n",ans);
}
T3 树上路径
emmm细节有点多,样例全过了,一交就蛋了。。。。
肯定存在一条边把这两条路径分为两部分,那么枚举这条边(就是直接dfs)然后找到两端的联通块的直径更新答案
考虑如何找到两端的直径,首先维护出一个点子树里经过它的最长链和不经过它的最长链,然后再维护出自己兄弟子树里
通过与不通过兄弟自己的最长链,然后在dfs的时候直接传参就行了
#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
#define ll long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int maxn=5e5+5;
int n,ans[maxn],maxx[maxn],dps[maxn],mx[maxn],dep[maxn];
vector<int>vec[maxn],xd[maxn],dian[maxn]; vector<pii>zx[maxn];
int zd[maxn],cd[maxn],tong[maxn];
inline void dfs1(int x,int f)
{
dep[x]=dep[f]+1;dps[x]=dep[x];mx[x]=1;
for(int i=0;i<vec[x].size();i++)
{
int y=vec[x][i];
if(y==f) continue; dfs1(y,x);
maxx[x]=max(maxx[x],max(dps[y]-dep[x],max(maxx[y],mx[y])));
mx[x]=max(mx[x],dps[x]-dep[x]+dps[y]-dep[x]+1);
dps[x]=max(dps[x],dps[y]); zx[x].push_back(mp(0,0));
xd[x].push_back(dps[y]-dep[x]);
dian[x].push_back(y);
}
for(auto y:dian[x]) tong[dps[y]-dep[x]]++;
if(xd[x].size()>=2)
{
sort(xd[x].begin(),xd[x].end());
for(int i=0;i<dian[x].size();i++)
{
int y=dian[x][i];
int tmp1=dian[x].size()-1,tmp2=dian[x].size()-2,tmp3=dps[y]-dep[x];
if(tmp3==xd[x][tmp1]&&tong[xd[x][tmp1]]<=2) tmp1--,tmp2--;
else if(tmp3==xd[x][tmp2]&&tong[xd[x][tmp2]]==1) tmp2--;
zd[y]=xd[x][tmp1];if(tmp2>=0) cd[y]=xd[x][tmp2];
}
}
for(int i=0;i<dian[x].size();i++){int y=dian[x][i];tong[dps[y]-dep[x]]--;}
if(zx[x].size()>=2)
for(int i=1;i<zx[x].size();i++)
{int y=dian[x][i-1];zx[x][i].fi=max(max(zx[x][i-1].fi,dps[y]-dps[x]),max(maxx[y],mx[y]));}
if(zx[x].size()>=2)
for(int i=zx[x].size()-2;i>=0;i--)
{int y=dian[x][i+1];zx[x][i].se=max(max(zx[x][i+1].se,dps[y]-dps[x]),max(maxx[y],mx[y]));}
}
inline void chmax(int &x,int y){x=max(x,y);}
inline void dfs2(int x,int f,int j,int bj)
{
for(int i=0;i<dian[x].size();i++)
{
int y=dian[x][i];
int tmp1=max(j+zd[y],max(bj,zd[y]+1));
tmp1=max(tmp1,zd[y]+cd[y]+1);
tmp1=max(max(zx[x][i].fi,zx[x][i].se),tmp1);
chmax(ans[tmp1],max(maxx[y],mx[y]));
chmax(ans[max(maxx[y],mx[y])],tmp1);
dfs2(y,x,max(j+1,zd[y]+2),max(max(zd[y]+j,zd[y]+cd[y]+1),tmp1));
}
}
signed main()
{
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
n=read();
for(int i=1;i<n;i++)
{
int x=read(),y=read();
vec[x].push_back(y);
vec[y].push_back(x);
}
dfs1(1,0);dfs2(1,0,1,0);ll sum=0;
for(int i=n;i>=1;i--) ans[i]=max(ans[i],ans[i+1]);
for(int i=1;i<=n;i++) sum+=ans[i];
printf("%lld\n",sum);
}
T4 糖
单调队列优化一下贪心过程就OK了
#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int maxn=5e5+5;
int a[maxn],b[maxn],s[maxn],n,C,now,ans;
pii que[maxn];
signed main()
{
freopen("candy.in","r",stdin);
freopen("candy.out","w",stdout);
n=read();C=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=0;i<n;i++) b[i]=read(),s[i]=read();
int head=1,tail=0;
for(int i=0;i<n;i++)
{
int ji=0;
while(head<=tail&&que[head].fi<=s[i]){ji+=que[head].se;++head;}
if(ji){--head;que[head]=make_pair(s[i],ji);}
while(head<=tail&&que[tail].fi>=b[i])
{ans-=que[tail].fi*que[tail].se,now-=que[tail].se,--tail;}
if(i!=n)
{
que[++tail]=mp(b[i],C-now);
ans+=b[i]*(C-now);now=C;
int len=a[i+1]-a[i];now-=len;
while(head<=tail&&len>=que[head].se)len-=que[head].se,++head;
if(len)que[head].se-=len;
}
}
while(head<=tail)ans-=que[tail].fi*que[tail].se,tail--;;
printf("%lld\n",ans);
}