8.26NOIP Day11模拟赛
T1
好像是一道小清新数据结构题,但我没管那么多直接就推了个性质开始贪了,最后打了一大坨
感性理解一下,挤压后区间长度跑满 \(d\) 一定是不劣的,同时显然最优情况一定是两个端点中存在一个被取到过至少一次
所以我们就考虑双指针跑一下决策区间,然后维护三种 \((<l,mid,>r)\) 之间相邻的贡献,分讨一大堆东西然后左右端点各跑一遍就完事了。
码长 \(2.5\) 倍,时间 \(1/15\),空间 \(1/20\),优势在我!
#include<bits/stdc++.h>
#define int long long
#define N 200005
using namespace std;
int x[N],y[N],id[N];
bool cmp(int a,int b){return x[a]<x[b];}
signed main(){
int n,d;
scanf("%lld%lld",&n,&d);
for(int i=1;i<=n;i++){
scanf("%lld",&x[i]);
y[i]=i;
}
x[0]=x[1];
x[n+1]=x[n];
sort(y+1,y+n+1,cmp);
for(int i=1;i<=n;i++)id[y[i]]=i;
id[0]=id[1];
id[n+1]=id[n];
int cnt=0,now=1,ans=0,cnta=0,cntb=0,suma=0,sumb=0;
for(int i=1;i<=n;i++){
while(now<=n&&x[y[now]]<=x[y[i]]+d){
int v=y[i],u=y[now];
if(u>1){
if(id[u-1]<id[v]){
cnt-=d;
cnta++;
suma+=x[u];
}
else if(id[u-1]<now){
cntb--;
sumb-=x[u-1];
cnt+=abs(x[u]-x[u-1]);
}
else{
cntb++;
sumb+=x[u];
}
}
if(u<n){
if(id[u+1]<id[v]){
cnt-=d;
cnta++;
suma+=x[u];
}
else if(id[u+1]<now){
cntb--;
sumb-=x[u+1];
cnt+=abs(x[u]-x[u+1]);
}
else{
cntb++;
sumb+=x[u];
}
}
now++;
}
if(i>1){
int u=y[i-1];
if(u>1){
if(id[u-1]<id[u]){
cnta--;
suma-=x[u];
}
else if(id[u-1]<now){
cnta++;
suma+=x[u-1];
cnt-=abs(x[u]-x[u-1]);
}
else{
cntb--;
sumb-=x[u];
cnt+=d;
}
}
if(u<n){
if(id[u+1]<id[u]){
cnta--;
suma-=x[u];
}
else if(id[u+1]<now){
cnta++;
suma+=x[u+1];
cnt-=abs(x[u]-x[u+1]);
}
else{
cntb--;
sumb-=x[u];
cnt+=d;
}
}
}
ans=max(ans,cnt+suma-cnta*x[y[i]]+cntb*(x[y[i]]+d)-sumb);
}
cnt=0;
now=n;
cnta=0;
cntb=0;
suma=0;
sumb=0;
for(int i=n;i;i--){
while(now&&x[y[now]]>=x[y[i]]-d){
int v=y[i],u=y[now];
if(u>1){
if(id[u-1]<now){
cnta++;
suma+=x[u];
}
else if(id[u-1]<id[v]){
cnta--;
suma-=x[u-1];
cnt+=abs(x[u]-x[u-1]);
}
else{
cnt-=d;
cntb++;
sumb+=x[u];
}
}
if(u<n){
if(id[u+1]<now){
cnta++;
suma+=x[u];
}
else if(id[u+1]<id[v]){
cnta--;
suma-=x[u+1];
cnt+=abs(x[u]-x[u+1]);
}
else{
cnt-=d;
cntb++;
sumb+=x[u];
}
}
now--;
}
if(i<n){
int u=y[i+1];
if(u>1){
if(id[u-1]<now){
cnt+=d;
cnta--;
suma-=x[u];
}
else if(id[u-1]<id[u]){
cntb++;
sumb+=x[u-1];
cnt-=abs(x[u]-x[u-1]);
}
else{
cntb--;
sumb-=x[u];
}
}
if(u<n){
if(id[u+1]<now){
cnt+=d;
cnta--;
suma-=x[u];
}
else if(id[u+1]<id[u]){
cntb++;
sumb+=x[u+1];
cnt-=abs(x[u]-x[u+1]);
}
else{
cntb--;
sumb-=x[u];
}
}
}
ans=max(ans,cnt+suma-cnta*(x[y[i]]-d)+cntb*x[y[i]]-sumb);
}
printf("%lld\n",ans);
return 0;
}
T2
题目给出的是dfs序,再加上相邻叶结点连边,所以子树内只可能会有最左边和最右边的点连到外面去
考虑设计状态维护以每个子树内根节点是否匹配, 最左边的叶⼦是否匹配,最右边的叶⼦是否匹配的⽅案数,然后巨大分讨
#include<bits/stdc++.h>
#define mod 998244353
#define N 100005
#define int long long
using namespace std;
int fa[N],dp[N][2][2][2],f[N][2][2][2],R[N];
signed main(){
int n;
scanf("%lld",&n);
for(int i=2;i<=n;i++)scanf("%lld",&fa[i]);
for(int i=n;i>=1;i--)R[i]=i;
for(int i=n;i>=1;i--)R[fa[i]]=max(R[fa[i]],R[i]);
for(int i=1;i<=n;i++)if(i==R[i])dp[i][0][0][0]=dp[i][1][1][0]=dp[i][1][0][1]=1;
for(int i=n;i>=2;i--){
int u=i,v=fa[i];
if(R[u]==R[v]){
dp[v][0][0][0]=(dp[u][0][0][0]+dp[u][1][0][0])%mod;
dp[v][0][0][1]=(dp[u][0][0][1]+dp[u][1][0][1])%mod;
dp[v][0][1][0]=(dp[u][0][1][0]+dp[u][1][1][0])%mod;
dp[v][0][1][1]=(dp[u][0][1][1]+dp[u][1][1][1])%mod;
dp[v][1][0][0]=dp[u][0][0][0];
dp[v][1][0][1]=dp[u][0][0][1];
dp[v][1][1][0]=dp[u][0][1][0];
dp[v][1][1][1]=dp[u][0][1][1];
}
else{
f[v][0][0][0]=(dp[v][0][0][0]*dp[u][0][0][0]+dp[v][0][1][0]*dp[u][0][0][1]+dp[v][0][0][0]*dp[u][1][0][0]+dp[v][0][1][0]*dp[u][1][0][1])%mod;
f[v][0][0][1]=(dp[v][0][0][1]*dp[u][0][0][0]+dp[v][0][1][1]*dp[u][0][0][1]+dp[v][0][0][1]*dp[u][1][0][0]+dp[v][0][1][1]*dp[u][1][0][1])%mod;
f[v][0][1][0]=(dp[v][0][0][0]*dp[u][0][1][0]+dp[v][0][1][0]*dp[u][0][1][1]+dp[v][0][0][0]*dp[u][1][1][0]+dp[v][0][1][0]*dp[u][1][1][1])%mod;
f[v][0][1][1]=(dp[v][0][0][1]*dp[u][0][1][0]+dp[v][0][1][1]*dp[u][0][1][1]+dp[v][0][0][1]*dp[u][1][1][0]+dp[v][0][1][1]*dp[u][1][1][1])%mod;
f[v][1][0][0]=(dp[v][0][0][0]*dp[u][0][0][0]+dp[v][0][1][0]*dp[u][0][0][1]+dp[v][1][0][0]*dp[u][0][0][0]+dp[v][1][1][0]*dp[u][0][0][1]+dp[v][1][0][0]*dp[u][1][0][0]+dp[v][1][1][0]*dp[u][1][0][1])%mod;
f[v][1][0][1]=(dp[v][0][0][1]*dp[u][0][0][0]+dp[v][0][1][1]*dp[u][0][0][1]+dp[v][1][0][1]*dp[u][0][0][0]+dp[v][1][1][1]*dp[u][0][0][1]+dp[v][1][0][1]*dp[u][1][0][0]+dp[v][1][1][1]*dp[u][1][0][1])%mod;
f[v][1][1][0]=(dp[v][0][0][0]*dp[u][0][1][0]+dp[v][0][1][0]*dp[u][0][1][1]+dp[v][1][0][0]*dp[u][0][1][0]+dp[v][1][1][0]*dp[u][0][1][1]+dp[v][1][0][0]*dp[u][1][1][0]+dp[v][1][1][0]*dp[u][1][1][1])%mod;
f[v][1][1][1]=(dp[v][0][0][1]*dp[u][0][1][0]+dp[v][0][1][1]*dp[u][0][1][1]+dp[v][1][0][1]*dp[u][0][1][0]+dp[v][1][1][1]*dp[u][0][1][1]+dp[v][1][0][1]*dp[u][1][1][0]+dp[v][1][1][1]*dp[u][1][1][1])%mod;
dp[v][0][0][0]=f[v][0][0][0];
dp[v][0][0][1]=f[v][0][0][1];
dp[v][0][1][0]=f[v][0][1][0];
dp[v][0][1][1]=f[v][0][1][1];
dp[v][1][0][0]=f[v][1][0][0];
dp[v][1][0][1]=f[v][1][0][1];
dp[v][1][1][0]=f[v][1][1][0];
dp[v][1][1][1]=f[v][1][1][1];
}
}
printf("%lld\n",(dp[1][0][0][0]+dp[1][0][1][1]+dp[1][1][0][0]+dp[1][1][1][1])%mod);
return 0;
}
T3
忘了,好像是要写网络流
T4
忘了,怎么又是生成函数

浙公网安备 33010602011771号