今天居然考了一套题。NOIP2015D2。

  这是当年的战绩:

  

  360的一等奖线。好强啊!

  之前做过2015的D1,但我确实不会做landlord……今天曾祥瑞学长和林可学姐都来了,他们说,朱昶宇AK,看见landlord时蒙了便按照自己平时的套路来打程序,看见transport时蒙了便暴力乱搞……

  我不想说,经过了不懈的努力,我才让transport成了95,而他轻轻松松暴力乱搞过了最后那个防AK点。我不想说,当时全省只有他一个人A了这道题。

  太强了!

  好的,现在我们该静一静了。

  第一题,stone,典型的二分答案例题(套贪心),但是二分策略确实很伤人头脑。

 #define PN "stone"
#include <cstdio>
int l, n, m, d[];
int main() {
freopen(PN".in","r",stdin);
freopen(PN".out","w",stdout);
scanf("%d%d%d",&l,&n,&m);
d[]=;for( int i = ; i <= n; i++ ) scanf("%d",&d[i]);d[n+]=l;
int lf=,rg=l;
while(lf<=rg) {
int mid=(lf+rg)>>, pos=, num=;
for( int i = ; i <= n+; i++ ) if(d[i]-d[pos]>=mid) pos=i;else num++;
if(num<=m) lf=mid+;
else rg=mid-;//?
}
printf("%d\n",rg);
return ;
}

stone

  第二题,那啥,很明显是可以套路化的,不知道难在哪里。

 #define PN "substring"
#include <cstdio>
#include <cstring>
#include <algorithm>
int n, m, p, f[][][];
char A[], B[];
inline int add(int a,int b) {static int MOD=1e9+;if(a-MOD+b>) return a-MOD+b;return a+b;}
int main() {
freopen(PN".in","r",stdin);
freopen(PN".out","w",stdout);
scanf("%d%d%d%s%s",&n,&m,&p,A,B);
memset(f,,sizeof(f));f[][][]=;
for( int i = ; i <= n; i++ ) for( int j = std::min(i,m); j >= ; j-- ) for( int k = std::min(i,p); k >= ; k-- ) {
f[][j][k]=add(f[][j][k],f[][j][k]);
if(j!=&&A[i-]==B[j-]) f[][j][k]=add(add(f[][j-][k],f[][j-][k-]),f[][j-][k-]);
else f[][j][k]=;
}
printf("%d\n",add(f[][m][p],f[][m][p]));
return ;
}

substring

  第三题,transport,这道题理论上需要先处理处每个方案的LCA,以及这一段的距离。然后,我们就可以愉快的二分答案。找出那些超了限额的方案,看他们所共有的线路。最值减最值,与mid比较一番,就可以愉快的得出结果了。但是n,m<=300000伤不起啊。

  好的,不多说了。最后一题挂个代码吧。

 #define PN "transport"
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
template<class T>inline void readin(T &res) {
static char ch;while((ch=getchar())<''||ch>'');
res=ch-;while((ch=getchar())>=''&&ch<='')res=(res<<)+(res<<)+ch-;
} const int N = +;
const int M = +;
struct EDGE {int v, upre, w;}g[N];
int head[N], ne=;
inline void adde(int u,int v,int w) {g[++ne]=(EDGE){v,head[u],w},head[u]=ne;} int n, m, u, v, w, s, t; const int S = ;
int dep[N], anc[N][S+], dis[N], edg[N], A[M], B[M], C[M], LEN[M];
void DFS(int u,int fa) {
anc[u][]=fa;
for( int j = ; j <= S; j++ ) anc[u][j]=anc[anc[u][j-]][j-];
for( int i = head[u]; i; i = g[i].upre ) {
int v=g[i].v;
if(v==fa) continue;
edg[v]=g[i].w;dep[v]=dep[u]+;dis[v]=dis[u]+g[i].w;DFS(v,u);
}
} int lca(int u,int v) {
if(dep[u]<dep[v]) swap(u,v);
for( int t=dep[u]-dep[v],p=; t; t>>=,p++ ) if(t&) u=anc[u][p];
if(u==v) return u;
for( int p = S; anc[u][]!=anc[v][]; p-- ) if(anc[u][p]!=anc[v][p]) u=anc[u][p], v=anc[v][p];
return anc[u][];
} int counter, maxl=, flag[N], ans;
void DFS1(int u,int fa) {
for( int i = head[u]; i; i = g[i].upre ) {
int v = g[i].v;
if(v==fa) continue;
DFS1(v,u);
flag[u]+=flag[v];
}
if(flag[u]==counter) ans=max(ans,edg[u]);
}
bool check(int limit) {
ans=;counter=;memset(flag,,sizeof(flag));for( int i = ; i <= m; i++ ) if(LEN[i]>limit) counter++, flag[A[i]]++, flag[B[i]]++, flag[C[i]]-=;
DFS1(,);return maxl-ans<=limit;
} int main() {
freopen(PN".in","r",stdin);
freopen(PN".out","w",stdout);
readin(n);readin(m);for( int i = ; i < n; i++ ) {readin(u);readin(v);readin(w);adde(u,v,w);adde(v,u,w);}
DFS(,);
for( int i = ; i <= m; i++ ) {
readin(A[i]);readin(B[i]);C[i]=lca(A[i],B[i]);
LEN[i]=dis[A[i]]+dis[B[i]]-dis[C[i]]*;maxl=max(maxl,LEN[i]);
}
int lf=, rg=maxl-;
while(lf<=rg) {
int mid=(lf+rg)>>;
if(check(mid)) rg=mid-;
else lf=mid+;
}
printf("%d\n",rg+);
return ;
}

transport

  后来:啊啊啊啊啊。我把最开始求LCA的ST表倍增换成了并查集tarjan,在教师老年机上又WA又T(后来经过考究,是因为u==v时tarjan的bug)。但我在BZOJ上交了一下。 

并查集tarjan  Accepted 36200 kb  9528 ms
ST表倍增 Accepted 46452 kb 9700 ms

  是为什么?人品吗?

 /**************************************************************
Problem: 4326
User: Doggu
Language: C++
Result: Accepted
Time:9528 ms
Memory:36200 kb
****************************************************************/ #define PN "transport"
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
template<class T>inline void readin(T &res) {
static char ch;while((ch=getchar())<''||ch>'');
res=ch-;while((ch=getchar())>=''&&ch<='')res=(res<<)+(res<<)+ch-;
} const int N = +;
const int M = +;
struct EDGE {int v, upre, w, lca;}g[N*], r[M*];
int head[N], ne=, read[N], re=;
inline void adde(int u,int v,int w) {g[++ne]=(EDGE){v,head[u],w},head[u]=ne;}
inline void addr(int u,int v,int w) {r[++re]=(EDGE){v,read[u],w},read[u]=re;} int n, m, u, v, w, s, t; int fax[N], dis[N], edg[N], A[M], B[M], C[M], LEN[M];
bool vis[N];
int find(int x) {
if(fax[x]==x) return x;
return fax[x]=find(fax[x]);
}
void DFS(int u,int fa) {
for( int i = head[u]; i; i = g[i].upre ) {
int v=g[i].v;
if(v==fa) continue;
edg[v]=g[i].w;dis[v]=dis[u]+g[i].w;DFS(v,u);
fax[v]=find(u);vis[v]=;
}
for( int i = read[u]; i; i = r[i].upre ) if(vis[r[i].v]) r[i].lca=find(r[i].v);
} int counter, maxl=, flag[N], ans;
void DFS1(int u,int fa) {
for( int i = head[u]; i; i = g[i].upre ) {
int v = g[i].v;
if(v==fa) continue;
DFS1(v,u);
flag[u]+=flag[v];
}
if(flag[u]==counter) ans=max(ans,edg[u]);
}
bool check(int limit) {
ans=;counter=;memset(flag,,sizeof(flag));for( int i = ; i <= m; i++ ) if(LEN[i]>limit) counter++, flag[A[i]]++, flag[B[i]]++, flag[C[i]]-=;
DFS1(,);return maxl-ans<=limit;
} int main() {
//freopen(PN".in","r",stdin);
//freopen(PN".out","w",stdout);
readin(n);readin(m);for( int i = ; i < n; i++ ) {readin(u);readin(v);readin(w);adde(u,v,w);adde(v,u,w);}
for( int i = ; i <= m; i++ ) {readin(A[i]);readin(B[i]);addr(A[i],B[i],i);addr(B[i],A[i],i);}
for( int i = ; i <= n; i++ ) fax[i]=i;memset(vis,,sizeof(vis));
DFS(,);for( int i = ; i <= re; i++ ) if(r[i].lca) C[r[i].w]=r[i].lca;
for( int i = ; i <= m; i++ ) LEN[i]=dis[A[i]]+dis[B[i]]-dis[C[i]]*, maxl=max(maxl,LEN[i]);
int lf=, rg=maxl-;
while(lf<=rg) {
int mid=(lf+rg)>>;
if(check(mid)) rg=mid-;
else lf=mid+;
}
printf("%d\n",rg+);
return ;
}

Tarjan并查集

 /**************************************************************
Problem: 4326
User: Doggu
Language: C++
Result: Accepted
Time:9700 ms
Memory:46452 kb
****************************************************************/ #define PN "transport"
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
template<class T>inline void readin(T &res) {
static char ch;while((ch=getchar())<''||ch>'');
res=ch-;while((ch=getchar())>=''&&ch<='')res=(res<<)+(res<<)+ch-;
} const int N = +;
const int M = +;
struct EDGE {int v, upre, w;}g[N*];
int head[N], ne=;
inline void adde(int u,int v,int w) {g[++ne]=(EDGE){v,head[u],w},head[u]=ne;} int n, m, u, v, w, s, t; const int S = ;
int dep[N], anc[N][S+], dis[N], edg[N], A[M], B[M], C[M], LEN[M];
void DFS(int u,int fa) {
anc[u][]=fa;
for( int j = ; j <= S; j++ ) anc[u][j]=anc[anc[u][j-]][j-];
for( int i = head[u]; i; i = g[i].upre ) {
int v=g[i].v;
if(v==fa) continue;
edg[v]=g[i].w;dep[v]=dep[u]+;dis[v]=dis[u]+g[i].w;DFS(v,u);
}
} int lca(int u,int v) {
if(dep[u]<dep[v]) swap(u,v);
for( int t=dep[u]-dep[v],p=; t; t>>=,p++ ) if(t&) u=anc[u][p];
if(u==v) return u;
for( int p = S; anc[u][]!=anc[v][]; p-- ) if(anc[u][p]!=anc[v][p]) u=anc[u][p], v=anc[v][p];
return anc[u][];
} int counter, maxl=, flag[N], ans;
void DFS1(int u,int fa) {
for( int i = head[u]; i; i = g[i].upre ) {
int v = g[i].v;
if(v==fa) continue;
DFS1(v,u);
flag[u]+=flag[v];
}
if(flag[u]==counter) ans=max(ans,edg[u]);
}
bool check(int limit) {
ans=;counter=;memset(flag,,sizeof(flag));for( int i = ; i <= m; i++ ) if(LEN[i]>limit) counter++, flag[A[i]]++, flag[B[i]]++, flag[C[i]]-=;
DFS1(,);return maxl-ans<=limit;
} int main() {
//freopen(PN".in","r",stdin);
//freopen(PN".out","w",stdout);
readin(n);readin(m);for( int i = ; i < n; i++ ) {readin(u);readin(v);readin(w);adde(u,v,w);adde(v,u,w);}
DFS(,);
for( int i = ; i <= m; i++ ) {
readin(A[i]);readin(B[i]);C[i]=lca(A[i],B[i]);
LEN[i]=dis[A[i]]+dis[B[i]]-dis[C[i]]*;maxl=max(maxl,LEN[i]);
}
int lf=, rg=maxl-;
while(lf<=rg) {
int mid=(lf+rg)>>;
if(check(mid)) rg=mid-;
else lf=mid+;
}
printf("%d\n",rg+);
return ;
}

ST表倍增

  不过,昶宇哥确实快炸了……我犯大不韪地交了一下他的,却发现早有人交过了……

14 1182623 ddyyff 36952 KB 2992 MS C++ 4689 B 2015-12-05 09:31:34
15 2139716(3) Doggu 36972 KB 2992 MS C++ 4689 B 2017-07-02 08:57:28

  

NOIP2015D2总结的更多相关文章

随机推荐

  1. 打包应用和构建Docker镜像(docker在windows上)

    在构建Docker时编译应用 一般有两种方法在构建镜像时进行打包应用.第一种方法就是使用基本的镜像,该镜像包括应用平台和构建工具,因此在Dockerfile中,复制源代码到镜像中并在构建镜像时编译ap ...

  2. Sony深度学习框架 - Neural Network Console - 教程(1)- 原来深度学习可以如此简单

    “什么情况!?居然不是黑色背景+白色文字的命令行.对,今天要介绍的是一个拥有白嫩的用户界面的深度学习框架.” 人工智能.神经网络.深度学习,这些概念近年已经涌入每个人的生活中,我想很多人早就按捺不住想 ...

  3. 多线程分段下载研究的python实现(一)

    我一直对下载文件比较感兴趣.现在我下载文件大部分是用迅雷,但迅雷也有一些不如意的地方,内存占用大,一些不必要的功能太多,不可定制.尤其是最后一点.现在有些下载对useragent,cookie,aut ...

  4. Node.js开发入门—套接字(socket)编程

    Node.js的net模块提供了socket编程接口,方便我们利用较为底层的套接字接口来实现应用协议.这次我们看一个简单的回显服务器示例,包括服务端和客户端的代码. 代码 分服务器和客户端两部分来说吧 ...

  5. [2019BUAA软件工程]第0次个人作业

    我 & 计算机 写在前面   撰写本博客时,笔者正就读北航计算机系大三下的软件工程课程.借由这次博客作业的机会,笔者从高考时与计算机专业结缘.大学对计算机的学习以及对未来的计划三方面进行了些许 ...

  6. jsp九大内置对象之一request

    request对象,目的是用来获取客户端的请求. 主要方法有: request.getMethod();                      // 获取提交请求的方式 request.getPr ...

  7. FileInputStream 读取文件数据的输入字节流

    package com.inputstream; /* File类: 用于描述一个文件或者文件夹的. 通过File对象我们可以读取文件或者文件夹的属性数据,如果我们需要读取文件的内容数据,那么我们需要 ...

  8. dazhewang数据库初设计

    mysql> use dazhe; Database changed mysql> create table shops(id int primary key auto_increment ...

  9. 【转】python 三种遍历list的方法

    [转]python 三种遍历list的方法 #!/usr/bin/env python # -*- coding: utf-8 -*- if __name__ == '__main__': list ...

  10. java实现中值滤波均值滤波拉普拉斯滤波

    目录 来对下面的图像滤波,其实就是对各个像素点进行数学运算的过程 均值滤波 中值滤波 拉普拉斯滤波 Sobel滤波 注意 来对下面的图像滤波,其实就是对各个像素点进行数学运算的过程 均值滤波 均值滤波 ...