【noip 2015】提高组
(感觉自己并没有什么写题解的必要啊……做点补充好了,顺便扔代码
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】提高组的更多相关文章
- NOIP 2015提高组复赛
神奇的幻方 题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,……,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第 ...
- NOIP 2015 提高组 Day2
期望得分:100+10+60=170 实际得分:100+10+35=145 http://www.cogs.pro/cogs/page/page.php?aid=16 T1 跳石头 时间限制:1 s ...
- NOIP 2015 提高组 Day1
期望得分:100+100+100=300 实际得分:100+100+45=245 T3 相似的代码 复制过去 没有改全,痛失55分 http://www.cogs.pro/cogs/page/page ...
- noip 2015 提高组
算是填个坑吧 , QwQ Day 1 第一题很水,就是考代码能力 ,直接贴代码. #include <iostream> #include <cstdlib> #include ...
- NOIP 2008提高组第三题题解by rLq
啊啊啊啊啊啊今天已经星期三了吗 那么,来一波题解吧 本题地址http://www.luogu.org/problem/show?pid=1006 传纸条 题目描述 小渊和小轩是好朋友也是同班同学,他们 ...
- [NOIp 1998 提高组]Probelm 2 连接多位数【2011百度实习生笔试题】
/*====================================================================== [NOIp 1998 提高组]Probelm 2 连接 ...
- NOIP 2014 提高组 题解
NOIP 2014 提高组 题解 No 1. 生活大爆炸版石头剪刀布 http://www.luogu.org/problem/show?pid=1328 这是道大水题,我都在想怎么会有人错了,没算法 ...
- NOIP 2001 提高组 题解
NOIP 2001 提高组 题解 No 1. 一元三次方程求解 https://vijos.org/p/1116 看见有人认真推导了求解公式,然后猥琐暴力过的同学们在一边偷笑~~~ 数据小 暴力枚举即 ...
- 最优贸易 NOIP 2009 提高组 第三题
题目描述 C 国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市.任意两个 城市之间最多只有一条道路直接相连.这 m 条道路中有一部分为单向通行的道路,一部分 为双向通行的道路 ...
- NOIP 2006 提高组 t1 能量项链
题目描述 在Mars星球上,每个Mars人都随身佩带着一串能量项链.在项链上有N颗能量珠.能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数.并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定 ...
随机推荐
- Diagnostic Trouble Code诊断故障码
所有电子控制单元(ECU)都会根据整车厂规范要求对相关故障进行记录,并储存在NVM(也称作EEPROM)相当于平常电脑上硬盘里.除故障代码外,还会记录故障发生时相关整车情况(如供电电压,环境温度 ...
- kafka命令行脚本使用
zookeeper集群部署:http://www.cnblogs.com/ding2016/p/8280696.html kafka集群部署:http://www.cnblogs.com/ding20 ...
- 20165223《Java程序设计》第八周Java学习总结
教材学习内容总结 第12章-JAVA多线程机制 要点 Java中的线程 Thread类与线程的创建 线程的常用方法 线程同步 协调同步的线程 线程联合 GUI线程 计时器线程 教材学习中的问题和解决过 ...
- Shiro中的Rememberme后出现浏览器500错误
问题详述:在Shiro中添加Remember me功能后,只要勾选Remember me选项为true的时候,浏览器就会跳转到一个不可达页面,并且在Chrome中显示HTTP 500错误. 问题追踪: ...
- A1034. Head of a Gang
One way that the police finds the head of a gang is to check people's phone calls. If there is a pho ...
- 第二十五篇-Android 应用资源
这里介绍android的一些资源文件. 以一个登录界面为例. layout.xml <?xml version="1.0" encoding="utf-8" ...
- Good Bye 2018
Good Bye 2018 2018年最后一场CF,OVER! 弱弱的我只能做出3道A,B,D~~~~ 最后几分钟,感觉找到了C题的规律,结束的那一刻,提交了一发 "Wrong answer ...
- bzoj2819 DFS序 + LCA + 线段树
https://www.lydsy.com/JudgeOnline/problem.php?id=2819 题意:树上单点修改及区间异或和查询. 思维难度不高,但是题比较硬核. 整体思路是维护每一个结 ...
- jenkins配置小结
启动jenkins:javaw -jar -Dhudson.model.DirectoryBrowserSupport.CSP= jenkins.war --httpPort=8001 wget h ...
- go vendor管理Golang项目依赖
解决的问题 将源码拷贝到当前工程的vendor目录下,这样打包当前的工程代码到任意机器的$GOPATH/src下都可以通过编译. govendor 1.安装 go get -u -v github.c ...