先扔一份写的超级详细的题解。   -Day1-    -Day2-

(感觉自己并没有什么写题解的必要啊……做点补充好了,顺便扔代码

D1T1.神奇的幻方

题目链接

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,a[][];
int main()
{
scanf("%d",&n);
int mid=n/+,x=,y=mid;
a[][mid]=;
for(int i=;i<=n*n;i++)
{
if(x==&&y!=n)x=n,y++;
else if(x!=&&y==n)x--,y=;
else if(x==&&y==n)x++;
else
{
if(a[x-][y+])x++;
else x--,y++;
}
a[x][y]=i;
}
for(int i=;i<=n;i++)
{
for(int j=;j<=n;j++)
printf("%d ",a[i][j]);
printf("\n");
}
return ;
}

D1T2.信息传递

题目链接

拓扑排序,找到最短环的长度。

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=;
int n,to[N],in[N],ans=0x3f3f3f3f;
bool f[N];
int read()
{
int x=,f=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
int main()
{
n=read();
for(int i=;i<=n;i++)
to[i]=read(),in[to[i]]++;
for(int i=;i<=n;i++)
if(in[i]==)in[to[i]]--;
for(int i=;i<=n;i++)
{
if(in[i]==||f[i])continue;
int st=i,ed=i,sum=;
f[i]=true;
while(to[ed]!=st)
sum++,ed=to[ed],f[ed]=true;
ans=min(ans,sum+);
}
printf("%d",ans);
return ;
}

D1T3.斗地主

题目链接

一道真·很不想写的题。留个坑?回来填坑了。

比想象中的好写……其实就是dfs,vijos上的100组数据是真的有意思orz

注意A的转换,以及三带二不能带双王。

 #include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int inf=0x3f3f3f3f;
int T,n,x,y,ans,num[],a[];
int read()
{
int x=,f=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
int go()
{
bool f=false;
if(num[]==)f=true;
memset(a,,sizeof(a));
for(int i=;i<=;i++)a[num[i]]++;
int sum=;
while(a[]&&a[]>=)a[]--,a[]-=,f=false,sum++;
while(a[]&&a[]>=)a[]--,a[]-=,sum++;
while(a[]&&a[])a[]--,a[]--,f=false,sum++;
if(f)sum++,a[]--;
while(a[]&&a[])a[]--,a[]--,sum++;
while(a[]&&a[])a[]--,a[]--,sum++;
return sum+a[]+a[]+a[]+a[];
}
void dfs(int step)
{
if(step>=ans)return;
int t=go();
ans=min(ans,t+step);
for(int i=;i<=;i++)
{
int next=i;
while(num[next]>=)next++;
if(next-i>=)
{
for(int j=i+;j<=next-;j++)
{
for(int k=i;k<=j;k++)num[k]-=;
dfs(step+);
for(int k=i;k<=j;k++)num[k]+=;
}
}
}
for(int i=;i<=;i++)
{
int next=i;
while(num[next]>=)next++;
if(next-i>=)
{
for(int j=i+;j<=next-;j++)
{
for(int k=i;k<=j;k++)num[k]-=;
dfs(step+);
for(int k=i;k<=j;k++)num[k]+=;
}
}
}
for(int i=;i<=;i++)
{
int next=i;
while(num[next]>=)next++;
if(next-i>=)
{
for(int j=i+;j<=next-;j++)
{
for(int k=i;k<=j;k++)num[k]--;
dfs(step+);
for(int k=i;k<=j;k++)num[k]++;
}
}
}
}
int main()
{
T=read();n=read();
while(T--)
{
memset(num,,sizeof(num));
for(int i=;i<=n;i++)
{
x=read();y=read();
if(x==)x=;
else if(x)x--;
num[x]++;
}
ans=inf;
dfs();
printf("%d\n",ans);
}
return ;
}

D2T1.跳石头

题目链接

其实我第一次看到这道题的时候它叫河中跳房子……

先二分出答案,再判断答案是否合法(即需要移走的岩石数是否小于等于M

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int len,n,m,ans,a[];
int read()
{
int x=,f=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
bool check(int mid)
{
int base=,num=;
for(int i=;i<=n+;i++)
{
if(a[i]-base<mid)num++;
else base=a[i];
}
return num<=m;
}
int main()
{
len=read();n=read();m=read();
for(int i=;i<=n;i++)a[i]=read();
a[n+]=len;
int l=,r=len;
while(l<=r)
{
int mid=(l+r)>>;
if(check(mid))ans=mid,l=mid+;
else r=mid-;
}
printf("%d",ans);
return ;
}

D2T2.子串

题目链接

DP状态转移方程及解析详见开头题解(其实只是因为懒

这里提供自己写的一份滚动数组版本的代码。

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int modd=;
const int N=;
const int M=;
int n,m,K,f[][M][M],s[][M][M];
char a[N],b[M];
int read()
{
int x=,f=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
int main()
{
n=read();m=read();K=read();
scanf("%s%s",a,b);
s[][][]=s[][][]=;
for(int i=;i<=n;i++)
{
int ii=i%;
for(int j=;j<=m;j++)
if(a[i-]==b[j-])
for(int k=;k<=min(j,K);k++)
{
f[ii][j][k]=(s[ii^][j-][k-]+f[ii^][j-][k])%modd;
s[ii][j][k]=(s[ii^][j][k]+f[ii][j][k])%modd;
}
else
for(int k=;k<=min(j,K);k++)
{
f[ii][j][k]=;
s[ii][j][k]=s[ii^][j][k];
}
}
printf("%d",s[n%][m][K]);
return ;
}

D2T3.运输计划

题目链接

我们的大体思路依然是二分答案 → 判断是否合法。

首先,建树,dfs一发。因为我们后面需要树上倍增求最近公共祖先,所以要把一些会用到的信息先处理好。

需要特别注意的是,我们用v[i]代表结点i与其父亲结点的连边的权值

然后,我们把每个运输计划起点、终点的LCA以及路径长度先预处理出来。

对于二分出来的每个ans,我们可能需要将一条边边权赋为0来使所有方案的路径长度都小于或等于ans。倘若ans合法,则这条边满足以下条件:位于所有路径长度大于ans的计划的路径交集里,且权值大于路径长度最长的那条边-ans的值。否则ans不合法。

我们选择用sum数组维护树上前缀和来求交集,sum[i]代表结点i与其父亲结点的连边在所有路径长度大于ans的计划中出现的次数。若sum[i]=路径长度大于ans的计划的数量,则结点i与其父亲结点的连边在交集里。二分答案之后的判定过程为:O(m)扫一遍方案,对于所有路径长度大于我们二分出来的ans的方案,起点、终点sum+1,他们的LCAsum-2,然后再求前缀和。至于为什么要这么做……画图易得:如果结点i与其父亲结点的连边在方案x中,则方案x的起点或终点有且只有一个在结点i的子树内。然后就很简单明了了吧。

具体实现看代码咯。

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=;
int n,m,cnt,a,b,t;
int head[N],fa[N],deep[N],dis[N],x[N][],st[N],ed[N],lca[N],dist[N],sum[N],v[N];
bool f[N];
struct edge{int next,to,w;}e[N];
int read()
{
int x=,f=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
void insert(int u,int v,int w)
{
cnt++;e[cnt].to=v;e[cnt].w=w;e[cnt].next=head[u];head[u]=cnt;
}
void dfs(int k)
{
f[k]=true;
for(int i=;(<<i)<=deep[k];i++)
x[k][i]=x[x[k][i-]][i-];
for(int i=head[k];i;i=e[i].next)
{
if(!f[e[i].to])
{
x[e[i].to][]=k;
deep[e[i].to]=deep[k]+;
v[e[i].to]=e[i].w;
dis[e[i].to]=dis[k]+e[i].w;
dfs(e[i].to);
}
}
}
int find(int ri,int rj)
{
if(deep[ri]<deep[rj])swap(ri,rj);
int d=deep[ri]-deep[rj];
for(int i=;(<<i)<=d;i++)
if((<<i)&d)ri=x[ri][i];
if(ri==rj)return ri;
for(int i=;i>=;i--)
if((<<i)<=deep[rj]&&x[ri][i]!=x[rj][i])
ri=x[ri][i],rj=x[rj][i];
return x[ri][];
}
void query(int k)
{
for(int i=head[k];i;i=e[i].next)
if(e[i].to!=x[k][])
{
query(e[i].to);
sum[k]+=sum[e[i].to];
}
}
bool check(int ans)
{
int cntt=,cutt=;
for(int i=;i<=n;i++)sum[i]=;
for(int i=;i<=m;i++)
if(dist[i]>ans)
{
cntt++;cutt=max(cutt,dist[i]-ans);
sum[st[i]]++;sum[ed[i]]++;sum[lca[i]]-=;
}
query();
for(int i=;i<=n;i++)
if(sum[i]==cntt&&v[i]>=cutt)return true;
return false;
}
int main()
{
n=read();m=read();
for(int i=;i<n;i++)
{
a=read();b=read();t=read();
insert(a,b,t);insert(b,a,t);
}
dfs();
for(int i=;i<=m;i++)
{
st[i]=read();ed[i]=read();
lca[i]=find(st[i],ed[i]);
dist[i]=dis[st[i]]+dis[ed[i]]-*dis[lca[i]];
}
int L=,R=;
for(int i=;i<=m;i++)R=max(R,dist[i]);
while(L<=R)
{
int mid=(L+R)>>;
if(check(mid))R=mid-;
else L=mid+;
}
printf("%d\n",L);
return ;
}

【noip 2015】提高组的更多相关文章

  1. NOIP 2015提高组复赛

    神奇的幻方 题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,……,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第 ...

  2. NOIP 2015 提高组 Day2

    期望得分:100+10+60=170 实际得分:100+10+35=145 http://www.cogs.pro/cogs/page/page.php?aid=16 T1 跳石头 时间限制:1 s  ...

  3. NOIP 2015 提高组 Day1

    期望得分:100+100+100=300 实际得分:100+100+45=245 T3 相似的代码 复制过去 没有改全,痛失55分 http://www.cogs.pro/cogs/page/page ...

  4. noip 2015 提高组

    算是填个坑吧 , QwQ Day 1 第一题很水,就是考代码能力 ,直接贴代码. #include <iostream> #include <cstdlib> #include ...

  5. NOIP 2008提高组第三题题解by rLq

    啊啊啊啊啊啊今天已经星期三了吗 那么,来一波题解吧 本题地址http://www.luogu.org/problem/show?pid=1006 传纸条 题目描述 小渊和小轩是好朋友也是同班同学,他们 ...

  6. [NOIp 1998 提高组]Probelm 2 连接多位数【2011百度实习生笔试题】

    /*====================================================================== [NOIp 1998 提高组]Probelm 2 连接 ...

  7. NOIP 2014 提高组 题解

    NOIP 2014 提高组 题解 No 1. 生活大爆炸版石头剪刀布 http://www.luogu.org/problem/show?pid=1328 这是道大水题,我都在想怎么会有人错了,没算法 ...

  8. NOIP 2001 提高组 题解

    NOIP 2001 提高组 题解 No 1. 一元三次方程求解 https://vijos.org/p/1116 看见有人认真推导了求解公式,然后猥琐暴力过的同学们在一边偷笑~~~ 数据小 暴力枚举即 ...

  9. 最优贸易 NOIP 2009 提高组 第三题

    题目描述 C 国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市.任意两个 城市之间最多只有一条道路直接相连.这 m 条道路中有一部分为单向通行的道路,一部分 为双向通行的道路 ...

  10. NOIP 2006 提高组 t1 能量项链

    题目描述 在Mars星球上,每个Mars人都随身佩带着一串能量项链.在项链上有N颗能量珠.能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数.并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定 ...

随机推荐

  1. [HAOI2010]最长公共子序列(LCS+dp计数)

    字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列.令给定的字符序列X=“x0,x1,…,xm-1”,序列Y=“y0,y1,…,yk-1”是X ...

  2. poj2431(优先队列+贪心)

    题目链接:http://poj.org/problem?id=2431 题目大意:一辆卡车,初始时,距离终点L,油量为P,在起点到终点途中有n个加油站,每个加油站油量有限,而卡车的油箱容量无限,卡车在 ...

  3. Python3 与 C# 扩展之~基础拓展

      上次知识回顾:https://www.cnblogs.com/dotnetcrazy/p/9278573.html 代码裤子:https://github.com/lotapp/BaseCode ...

  4. Markdown基础(内含:锚点使用,使用HTML,新页面跳转,目录生成)

    Github样式显示参考:点我 之前说过用word写文章,这次说说Markdown写文章(推荐) 逆天推荐使用VSCode编写 装这个插件写作更方便: 内含:锚点使用,使用HTML,新页面跳转,目录生 ...

  5. 在 vue.js 中动态绑定 v-model

    在最近的项目中(基于vue),有一个需求就是通过 v-for 动态生成 input.在正常情况下,页面中的input数量是固定的,而且每个input绑定的v-model也是固定的,我们可以在 data ...

  6. C++基础知识-Day8

    2.类的作用域运算符 shadow 在我们之前讲的内容中,我们会发现一种情况,就是在我们在不同类中的打印函数我们都是尽量让其名字不同,那么为什么会有这种情况呢?首先我们来看一个函数 void func ...

  7. TODO maven学习笔记

    maven是什么? 我的体会 我理解得maven就是一个构建工具,可以做一些项目得整合操作,我们把一些常见得操作,封装在maven里面,并给它命名成 clean,test,compile,这些步骤都是 ...

  8. Luogu P3239 [HNOI2015]亚瑟王

    题目链接 \(Click\) \(Here\) 期望神题.最开始一直尝试推朴素一点的,逻辑上的\(DP\)式子,后来发现一直出锅,可能是我的式子没容斥对... 题解中给出的想法是这样的: 首先,如果直 ...

  9. redis的使用场景和基本数据类型

    一:redis使用的场景 redis是一个高性能的NoSQL数据库,特点是高性能,持久存储,适应高并发的应用场景. 下面看看它的使用场景1.取最新N个数据的操作比如取网站的最新文章,通过下面方式,我们 ...

  10. Python对象的创建和赋值

    创建类 类的定义以关键字class开头,之后跟着一个名字(用户定义)来标识这个类,并且以冒号结尾.类的内容以缩进(4个空格)表示,如下例的pass表示什么事情也不做. Python命名规则(以字母或者 ...