??大部分人都觉得T3是道不可做题去刚T1T2了,于是我就侥幸苟到了前面?

这场考试比较成功的就是快速水掉了T1T2的部分分,1h拿到88分起码为之后硬肝T3上了保险(赛后发现就算T3爆零也能rank15?)

剩下也就没什么了……T3的分完全是时间堆出来的,还有运气成分。因为当时第一个A掉了二分答案专题的奶牛健美操那道题,所以看到直径下意识想维护子树最长链+次长链,而且要不是前面两道题都不会我才不敢写那个恶心至极的分类讨论换根QAQ。单就方法而言,我打的东西其实挺无脑的,并没有思考太多针对本题的性质(要不然我还能只拿前两问的分?),最后莫名其妙不会第三问了。剩下的时间也没有打中途想到的二维莫队,觉得时间复杂度没有保证得不偿失。最后几十分钟没怎么拿分。

不过拿到T3的分至少证明自己代码能力和调试能力有了提升?(YY什么呢还是一如既往的菜)

看到自己前面的4位大佬都A题了,差一点碾碎我的LockeyA掉了T2,自己不过是三道题都骗了点分而已。前路还漫长啊。

A.施工

神dp。除了单调栈还有二次函数优化??

先丢个比较详细的题解

至于为什么尽量把坑填到和某一栋楼一样平是最优的,我也不会证

把当前位置$i$作为坑的右边缘,枚举坑的左边缘$j$,找能填的位置$k$,可得转移:

$f[i]=\sum \limits _{k=j+1}^{i-1}(t-h_k)^{2}+c*(h_j+h_i-2*t)+f[j]$

想怎么优化转移。首先要避免枚举所有位置。可以维护一个单调递减的单调栈,这样就确保栈里的元素一定可以转移给当前的$i$。

然后进行寻找最优解的优化。观察到这个转移方程是一个二次函数,化简一下就可以得到它的一次项、二次项、常数项系数。

那自变量$t$当然是取对称轴处($- \frac{b}{2a}$)最优啦,但是要注意取对称轴的答案是否合法。特判之。

计算对称轴四舍五入。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=1e6+5;
int n;
ll C,h[N],sum[N],Sum[N],f[N];
int s[N],top;
ll cacl(int l,int r,ll val)
{
ll a=r-l-1,b=-2*(sum[r-1]-sum[l]);
if(l)b-=C;if(r!=n+1)b-=C;
ll c=Sum[r-1]-Sum[l];
if(l)c+=h[l]*C;if(r!=n+1)c+=h[r]*C;
ll mid=-1LL*floor((double)b/((double)a*2.0)+0.5);
mid=max(mid,val);
if(l)mid=min(mid,h[l]);
if(r!=n+1)mid=min(mid,h[r]);
return mid*mid*a+mid*b+c;
}
int main()
{
scanf("%d%lld",&n,&C);
for(int i=1;i<=n;i++)
{
scanf("%lld",&h[i]);
sum[i]=sum[i-1]+h[i];
Sum[i]=Sum[i-1]+h[i]*h[i];
}
h[0]=h[n+1]=0x7fffffff;
for(int i=1;i<=n+1;i++)
{
if(i!=1&&i!=n+1)f[i]=f[i-1]+abs(h[i]-h[i-1])*C;
else f[i]=f[i-1];
while(top&&h[s[top]]<=h[i])f[i]=min(f[i],f[s[top-1]]+cacl(s[top-1],i,h[s[top]])),top--;
s[++top]=i;
}
cout<<f[n+1]<<endl;
return 0;
}

B.蔬菜

二维莫队水之。注意指针移动的先后顺序。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<map>
#include<algorithm>
using namespace std;
typedef long long ll;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int N=205,M=3e5+5;
int n,m,Q;
int a[N][N],type,bl,ans[M],res,bu[N*N];
map<int,int> link;
struct query
{
int x,y,xx,yy,id;
friend bool operator < (query p,query q)
{
return p.x/bl==q.x/bl?(p.y/bl==q.y/bl?(p.xx/bl==q.xx/bl?p.yy<q.yy:p.xx<q.xx):p.y<q.y):p.x<q.x;
}
}q[M];
void add(int x)
{
//cout<<"A "<<bu[x]<<endl;
res+=2*bu[x]+1;
bu[x]++;
}
void del(int x)
{
//cout<<"D "<<bu[x]<<endl;
res-=(2*bu[x]-1);
bu[x]--;
}
int main()
{
n=read();m=read();Q=read();
bl=pow(n*m,0.5)/pow(Q,0.25)+1.0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
int val=read();
if(!link[val])link[val]=++type;
a[i][j]=link[val];
}
for(int i=1;i<=Q;i++)
q[i].x=read(),q[i].y=read(),q[i].xx=read(),q[i].yy=read(),q[i].id=i;
sort(q+1,q+Q+1);
int x=1,y=1,xx=0,yy=0;
for(int i=1;i<=Q;i++)
{
int qx=q[i].x,qy=q[i].y,qxx=q[i].xx,qyy=q[i].yy;
//cout<<"POS "<<x<<' '<<y<<' '<<xx<<' '<<yy<<' '<<endl;
while(x>qx){x--;for(int j=y;j<=yy;j++)add(a[x][j]);}
while(x<qx){for(int j=y;j<=yy;j++)del(a[x][j]);x++;}
while(xx<qxx){xx++;for(int j=y;j<=yy;j++)add(a[xx][j]);}
while(xx>qxx){for(int j=y;j<=yy;j++)del(a[xx][j]);xx--;}
while(y>qy){y--;for(int j=x;j<=xx;j++)add(a[j][y]);}
while(y<qy){for(int j=x;j<=xx;j++)del(a[j][y]);y++;}
while(yy<qyy){yy++;for(int j=x;j<=xx;j++)add(a[j][yy]);}
while(yy>qyy){for(int j=x;j<=xx;j++)del(a[j][yy]);yy--;}
//cout<<x<<' '<<y<<' '<<xx<<' '<<yy<<' '<<endl;
ans[q[i].id]=res;
}
for(int i=1;i<=Q;i++)
printf("%d\n",ans[i]);
return 0;
}

C.联盟

我写的是恶心至极的换根……思维直接粗暴,细节稍多。

首先一遍dfs找出$x$的子树中的点到$x$的最长距离$dis[x]$,以及$x$子树中的直径$len[x]$,后者直接维护最长链和次长链就能得到。

然后考虑:如果我们断掉一条边,把树变成两个联通块,那么他们重新相连后的最短直径是?

很显然,联通块1的直径、联通块2的直径、两条直径的二分之一向上取整再相加后+1,这三者取$max$。最后那个的含义就是把两条直径的终点连在一起。

题解的做法是每个点维护子树前缀联通块和后缀联通块的直径端点即可快速合并,但我不太会维护端点,所以直接利用大量的链长信息进行换根dp,每次分类讨论得到结果。这样相当与枚举了每条边断掉后的结果,所以一定能遍历所有情况、找到所有可能断的边。

这个换根的过程要考虑很多东西:父亲到儿子的过程中子树直径已经求出,但外部联通块的直径需要额外维护。这个外部直径可能还是原来的外部直径,也有可能是经过刚刚被扔到外面的父亲的直径。

所以在转移的时候可能要维护最大值、次大值、再次大值。为什么?我们向儿子转移的时候需要除这个儿子的信息之外另外的两个极值来进行比较和拼凑出直径。如果这个儿子就是最大值的提供者,那肯定就不能用最大值来算外部直径了。总之很麻烦,看代码吧。(逃

这样就可以求出前两问的结果。至于第三问,先从第二问结果里随便挑一条边删了,然后取产生的这两个联通块的直径中点即可。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#define pa pair<int,int>
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int N=3e5+5;
int n;
int to[N<<1],head[N],nxt[N<<1],tot=1,id[N<<1],dis[N],len[N];
int s[N<<1],top,ans=0x3f3f3f3f,del;
pa e[N<<1];
void add(int x,int y,int i)
{
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
id[tot]=i;
}
void dfs1(int x,int f)
{
int maxx=0,secmax=0,num=0;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==f)continue;
dfs1(y,x);
len[x]=max(len[x],len[y]);
dis[x]=max(dis[x],dis[y]+1);
num++;
if(maxx<=dis[y])secmax=maxx,maxx=dis[y];
else if(secmax<dis[y])secmax=dis[y];
}
if(num<=1)len[x]=max(len[x],maxx+secmax+num);
else len[x]=max(len[x],maxx+secmax+2);
}
void dfs2(int x,int f,int l1,int l2,int p)
{
int nowmax=max(max(len[x],l1),1+(len[x]+1)/2+(l1+1)/2);
int num=0;
if(nowmax<ans)top=1,s[top]=p,ans=nowmax;
else if(nowmax==ans)s[++top]=p;
int maxx=0,secmax=0,thdmax=0,maxl=0,secmaxl=0;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==f)continue;
if(dis[y]>=maxx)thdmax=secmax,secmax=maxx,maxx=dis[y];
else if(dis[y]>=secmax)thdmax=secmax,secmax=dis[y];
else if(dis[y]>thdmax)thdmax=dis[y];
if(len[y]>=maxl)secmaxl=maxl,maxl=len[y];
else if(len[y]>secmaxl)secmaxl=len[y];
num++;
}
int m1,m2,m3,nowl,nl1,nl2;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==f)continue;
if(maxx==dis[y])m1=secmax,m2=thdmax;
else if(secmax==dis[y])m1=maxx,m2=thdmax;
else m1=maxx,m2=secmax;
if(maxl==len[y])m3=secmaxl;
else m3=maxl;
nowl=0;
if(num>1)nowl=max(nowl,l2+m1+1);
else nowl=max(nowl,l2);
if(num>2)nowl=max(nowl,m1+m2+2);
nl1=max(l1,max(m3,nowl));nl2=l2+1;
if(num>1)nl2=max(nl2,m1+2);
dfs2(y,x,nl1,nl2,id[i]);
}
}
int S,maxd,pre[N],T;
vector<int> link;
void dfs3(int x,int f,int dep)
{
if(dep>maxd)maxd=dep,S=x;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==f||del==id[i])continue;
dfs3(y,x,dep+1);
}
}
void dfs4(int x,int f,int dep)
{
if(dep>maxd)maxd=dep,T=x;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==f||del==id[i])continue;
pre[y]=x;
dfs4(y,x,dep+1);
}
}
void getdis(int x)
{
link.clear();
S=x;maxd=0;
dfs3(x,0,1);
maxd=0;
for(int i=1;i<=n;i++)
pre[i]=0;
dfs4(S,0,1);
int now=T;
while(now)link.push_back(now),now=pre[now];
} int main()
{
n=read();
for(int i=1;i<n;i++)
{
int x=read(),y=read();
add(x,y,i);add(y,x,i);
e[i]=make_pair(x,y);
}
dfs1(1,0);dfs2(1,0,0,0,0);
cout<<ans<<endl;
sort(s+1,s+top+1);
cout<<top<<' ';
for(int i=1;i<=top;i++)
cout<<s[i]<<' ';
putchar('\n');
del=s[top];
int node1=e[del].first,node2=e[del].second,node3,node4;
getdis(node1);
int sz=link.size();
node3=link[sz/2];
getdis(node2);
sz=link.size();
node4=link[sz/2];
cout<<node1<<' '<<node2<<' '<<node3<<' '<<node4<<endl;
return 0;
}

[CSP-S模拟测试50]反思+题解的更多相关文章

  1. csps模拟测试50反思

    又考崩了,T1一眼秒掉错误思路,然后迅速码完,并码完错误暴力,对拍拍上,以为AC.T2想到了二维莫队,发现是子任务就没去打,一直在想别的,T3最后想到60分打法,没有打完,也没时间暴力,挂掉.T2还有 ...

  2. [CSP-S模拟测试48]反思+题解

    状态很垃圾的一场考试.感觉“这么多分就够了”的心态很是在给自己拖后腿. 打开题面,第一页赫然写着:$Claris' Contest$. 吓得我差点手一抖关掉.不过后来想想似乎强到变态的人出的题都不是很 ...

  3. [CSP-S模拟测试47]反思+题解

    打开题面,T3似乎被换过了.(那我就更有理由直接弃掉了) T1是我最害怕的乱搞题,赶紧扔了看T2.发现是个sb板子?雨天的尾巴弱化版? 然而线段树合并早忘干净了(最近几道可以线段树合并的题都是用别的方 ...

  4. [NOIP模拟测试37]反思+题解

    一定要分析清楚复杂度再打!!!窝再也不要花2h20min用暴力对拍暴力啦!!! 雨露均沾(滑稽),尽量避免孤注一掷.先把暴力分拿全再回来刚正解. 即使剩下的时间不多了也优先考虑认真读题+打暴力而非乱搞 ...

  5. [NOIP模拟测试34]反思+题解

    不要陷入思维定势,如果长时间没有突破就要考虑更改大方向. 不要把简单问题复杂化. 做完的题就先放下,不管能拿多少分.不能过一段时间就回来调一下. $Solutions:$ A.次芝麻 因为$n+m$始 ...

  6. [NOIP模拟测试32]反思+题解

    又考挂了QAQ 总rank直接滑出前20 晚上考试脑子还算比较清醒,可惜都用来xjb乱想错误思路了. T1一眼推柿子,然而并没有头绪所以先码了个暴力.然后…… 一个垃圾暴力我调了1h,大概解决了两位数 ...

  7. 2019.8.14 NOIP模拟测试21 反思总结

    模拟测试20的还没改完先咕着 各种细节问题=错失190pts T1大约三分钟搞出了式子,迅速码完,T2写了一半的时候怕最后被卡评测滚去交了,然后右端点没有初始化为n…但是这样还有80pts,而我后来还 ...

  8. 2019.8.1 NOIP模拟测试11 反思总结

    延迟了一天来补一个反思总结 急匆匆赶回来考试,我们这边大家的状态都稍微有一点差,不过最后的成绩总体来看好像还不错XD 其实这次拿分的大都是暴力[?],除了某些专注于某道题的人以及远程爆踩我们的某学车神 ...

  9. 2019.8.9 NOIP模拟测试15 反思总结

    日常爆炸,考得一次比一次差XD 可能还是被身体拖慢了学习的进度吧,虽然按理来说没有影响.大家听的我也听过,大家学的我也没有缺勤多少次. 那么果然还是能力问题吗……? 虽然不愿意承认,但显然就是这样.对 ...

随机推荐

  1. Vagrant 手册之 Vagrantfile - Vagrant 设置 config.vagrant

    原文地址 配置的命名空间:config.vagrant config.vagrant 中的设置修改 Vagrant 自身的行为. 1. 可用设置 config.vagrant.host 设置运行 Va ...

  2. poj2236Wireless Network

    Description An earthquake takes place in Southeast Asia. The ACM (Asia Cooperated Medical team) have ...

  3. 永远让比较函数对相等的值返回false

    今天在刷OJ的时候,有一道题一直Runtime Error,查错出来是比较函数写挂掉了,但是不知道错误在哪,于是查阅资料:永远让比较函数对相等的值返回false 具体可点击此处查看分析:链接 另外,在 ...

  4. Mac003--Maven安装与环境变量配置

    Mac--Maven安装 一.应用brew安装maven及安装位置 打开终端,输入命令:brew install maven 参考博客:https://www.jianshu.com/p/230e0b ...

  5. window.location.href后携带参数

    JS文件中: window.location.href后可携带参数,但是不安全,虽然在技术上是可以实现的 1.传参:window.location.href = "RecordCare.as ...

  6. mysql: "Warning: Using a password on the command line interface can be insecure." 解决方法

    错误重现: 命令行或者shell脚本中执行以下命令,如果您当前服务器mysql版本是大于5.6的,则会出现警告:Warning: Using a password on the command lin ...

  7. maven配置本地仓库、maven配置阿里中央仓库、eclipse配置maven

    一.maven配置本地仓库路径 1.打开下载好的maven目录 (若没安装,可以看我写的安装步骤https://www.cnblogs.com/xjd-6/p/11344719.html) 2.进入c ...

  8. ES6---new Promise()讲解,Promise对象是用来干嘛的?

    ES6---new Promise()讲解,Promise对象是用来干嘛的? :https://blog.csdn.net/Wbiokr/article/details/79490390

  9. Docker配置远程访问

    近来学习Docker部署微服务,需要配置Docker的远程访问,由于实际环境和学习资料有出入,尝试着根据网上搜索的一些相关资料进行配置,未能成功.最终通过自己摸索,成功配置Docker远程访问.现和大 ...

  10. [Bzoj1051][HAOI2006]受欢迎的牛(tarjan)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1051 由题意可知,被所有牛仰慕的牛之间也互相仰慕,则最后的答案一定是唯一的强连通分量,如 ...