T1 玩具迷题

直通

思路:

  1.首先根据数据范围来看,储存小人的姓名开一个二维char数组即可(不会开爆)

  2.然后看他给出的样例以及条件什么的,能够确定出

      ①朝内向右,朝外向左均为+

      ②朝内向左,朝外向右均为-

  但是需要注意的是  加完之后超出最大数n-1(我从0开始进行计数),所以需要进行-n

            减完之后小于0的话,需要进行+n

  3.使问题更简单的方式 (y是移动步数) 

if(y>n)
y=y%(n+);

(不懂的话可以手动模拟一下)

上代码:

#include <iostream>
#include <cstdio>
using namespace std; const int Maxn = ;
const int Maxl = ;
int n,m,len;
bool f[Maxn];
char ssr[Maxn][Maxl]; int main() {
scanf("%d%d",&n,&m);
string sr;
for(int i=; i<n; ++i) {
scanf("%d",&f[i]);
cin>>sr;
len=sr.length();
for(int j=; j<len; ++j)
ssr[i][j]=sr[j];
}
int nxt=;
for(int i=,x,y; i<m; ++i) {
scanf("%d%d",&x,&y);
if(y>n)
y=y%(n+);
if(x) {//right
if(f[nxt]==) //朝内
nxt+=y;
else //朝外
nxt-=y;
}
else {//left
if(f[nxt]==) //朝内
nxt-=y;
else //朝外
nxt+=y;
}
if(nxt<)
nxt+=n;
if(nxt>=n)
nxt-=n;
}
for(int i=; ; ++i) {
if(ssr[nxt][i])
printf("%c",ssr[nxt][i]);
else
break;
}
return ;
}

T2 天天爱跑步

直通

思路:

  首先看到他给出这么详细的数据范围以及约定,不打一下暴力简直就是对不起他啊!所以首先我们这道题可以打暴力!

  ①首先来看前4个点中的前两个点的约定是起点等于终点,他的意思就是说明每一个点只存在于0秒的时候。

   而另外两个点的约定是所有的Wj均为0,所以这四个点再输入u,v的时候不用存边,只需要把起点终点以及每个点的Wj即可。

  具体的方法就是从1到m循环一遍若当前点的times为0,ans[该点的初始时间]++,最后按顺序输出ans数组即可

  核心代码如下:
  if(flag1||flag2) { //所有点的起点与终点相同 || 所有的Wj==0
for(int i=,u,v; i<n; ++i)
scanf("%d%d",&u,&v);
for(int i=; i<=n; ++i)
scanf("%d",&times[i]);
for(int i=; i<=m; ++i)
scanf("%d%d",&t[i].si,&t[i].ti);
for(int i=; i<=m; ++i) {
if(!times[t[i].si])
ans[t[i].si]++;
}
for(int i=; i<=n; ++i)
printf("%d ",ans[i]);
return ;
}

  ②然后我们来看第五个点,没有任何约定!但是看看数据范围跟前四个是一样的。

  等等!如果说数据范围的话来。。。。这个数据范围辣么小,眼前一亮!其实这不就是个搜索嘛!

  (这样子就可以将前五个点连接起来写一个解题方法了!)

  搜索思路:

    对于题目中给出的m个人的起止点进行dfs,记录下来他当前花费的时间以及他当前的父节点(以便于寻找并更新他的子节点)

    又因为在dfs中具有回退过程,若已经找到了正确的路线(即找到了终点now==end)后,

    可能还会再次进行搜索另外一些没有被搜索过,但是没有什么用的点(其实说白了就是在浪费时间),

    所以我们需要在回退过程中在进行更新p数组

  核心代码如下:(亲测搜索比特判还要快qwq,差不多快100多ms)
void dfs(int now,int ed,int time,int pre) {
if(now==ed) {
ok=true;
p[now][time]++;
return ;
}
if(ok) return ; //防止找到正确的路线之后在回退的过程中再次进行搜索一些无用的点,所以直接return
for(int i=head[now],v; i; i=e[i].next) {
v=e[i].to;
if(v==pre) continue; //不是子节点
dfs(v,ed,time+,now); //更新now,time,pre并继续搜索下去
if(ok)
{
p[now][time]++; //将正确的路线上的点的p进行更新
return;
}
}
}

  ③6.7.8个点:如果一棵树树退化成一条链的话,那么这个点上的观察员,

  就只能够看到从i+-times[i]这两个位置出发的人的就只需要进行加减再加上特判他存在即可

  我们需要知道:

    如果i能看到起点深度比他小的点,那么这个点的终点需要>=i

    如果i能看到起点深度比他大的点,那么这个点的终点需要<=i

  核心代码如下:
    for(int i=; i<=n; ++i) {
if(i-times[i]>) //若往前找有可能能够观察到人
for(int j=head[i-times[i]],v; j; j=e[j].next) {
v=e[j].to; //能够成功被观察到的这个点的编号为v(通过链表进行寻找)
if(i<=t[v].ti) //是从v点往后找,所以v点的目的地必须要大于i才可以,不然走不到i点
ans[i]++;
}
if(i+times[i]<=n) { //若往后找有可能能够观察到人
for(int j=head[i+times[i]],v; j; j=e[j].next) {
v=e[j].to;
if(i>=t[v].ti) //同理,因为上一种情况是从v点往后找,所以v点的目的地必须大于i,这一种情况则相反(小于)
ans[i]++;
}
}
}

  ④9-12点:所有的点的起点相同

    我们若设1号的深度是0,那么只有当那些观察员们所在节点的深度与当前这个节点的Wi是相同的,他才有可能能够观察到人。

    若不相等的话,直接输出0即可

    若相等的话,那么他就一定能够观察到所有经过他的人,也就是说以i为根的子树中拥有终点的个数有多少个

    所以首先可以bfs搜索出所有点的深度然后用一个简单的dfs来统计每一个节点的子树中拥有终点的个数(用son数组记录下来)

  核心代码如下:
void bfs() {
queue<Flag5>q;
cur.dep=; cur.id=; dad[]=;
q.push(cur);
while(!q.empty()) {
cur=q.front();
q.pop();
int u=cur.id;
for(int i=head[cur.id],v; i; i=e[i].next) {
v=e[i].to;
if(v==dad[u]) continue;
dad[v]=u; nxt.dep=cur.dep+;
nxt.id=v; deeps[v]=deeps[u]+;
q.push(nxt);
}
}
} void Dfs(int u) {
son[u]=sum[u];
for(int i=head[u],v; i; i=e[i].next) {
v=e[i].to;
if(v==dad[u]) continue;
Dfs(v);
son[u]+=son[v];
}
}

  至于正解什么的,待研究中。。。

神奇的第一反映233:

  天天就是天天。

上代码:

①暴力代码小汇总

#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
using namespace std; const int N = ;
const int Maxn = ;
int n,m;
int times[Maxn],ans[Maxn];
struct B {
int next,to;
}e[Maxn<<];
int top,head[Maxn];
inline void add(int u,int v) {
top++;e[top].to=v;
e[top].next=head[u];head[u]=top;
} bool flag,ok,flag1,flag2,flag4,flag5;
int p[N][N],sum[Maxn],deeps[Maxn],dad[Maxn],son[Maxn];
struct Flag4 {
int si,ti;
}t[Maxn];
struct Flag5 {
int dep,id;
}cur,nxt; void dfs(int now,int ed,int time,int pre) {
if(now==ed) {
ok=true;
p[now][time]++;
return ;
}
if(ok) return ; //防止找到正确的路线之后在回退的过程中再次进行搜索一些无用的点,所以直接return
for(int i=head[now],v; i; i=e[i].next) {
v=e[i].to;
if(v==pre) continue; //不是子节点
dfs(v,ed,time+,now); //更新now,time,pre并继续搜索下去
if(ok)
{
p[now][time]++; //将正确的路线上的点的p进行更新
return;
}
}
} void bfs() {
queue<Flag5>q;
cur.dep=; cur.id=; dad[]=;
q.push(cur);
while(!q.empty()) {
cur=q.front();
q.pop();
int u=cur.id;
for(int i=head[cur.id],v; i; i=e[i].next) {
v=e[i].to;
if(v==dad[u]) continue;
dad[v]=u; nxt.dep=cur.dep+;
nxt.id=v; deeps[v]=deeps[u]+;
q.push(nxt);
}
}
} void Dfs(int u) {
son[u]=sum[u];
for(int i=head[u],v; i; i=e[i].next) {
v=e[i].to;
if(v==dad[u]) continue;
Dfs(v);
son[u]+=son[v];
}
} int main() {
freopen("runninga.in","r",stdin);
freopen("runninga.out","w",stdout);
scanf("%d%d",&n,&m);
if(n%<=) flag=true;
// if(n%10==1) flag1=true;
// if(n%10==2) flag2=true;
if(n%==) flag4=true;
if(n%==) flag5=true;
if(flag) {
for(int i=,u,v; i<n; ++i) {
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
for(int i=; i<=n; ++i)
scanf("%d",&times[i]);
for(int i=,u,v; i<=m; ++i) {
scanf("%d%d",&u,&v);
ok=false;
dfs(u,v,,);
}
for(int i=; i<=n; ++i)
printf("%d ",p[i][times[i]]);
return ;
}
/*
if(flag1||flag2) { //所有点的起点与终点相同 || 所有的Wj==0
for(int i=1,u,v; i<n; ++i)
scanf("%d%d",&u,&v);
for(int i=1; i<=n; ++i)
scanf("%d",&times[i]);
for(int i=1; i<=m; ++i)
scanf("%d%d",&t[i].si,&t[i].ti);
for(int i=1; i<=m; ++i) {
if(!times[t[i].si])
ans[t[i].si]++;
}
for(int i=1; i<=n; ++i)
printf("%d ",ans[i]);
return 0;
}
*/
if(flag4) { //关系退化为一条链
for(int i=,u,v; i<n; ++i)
scanf("%d%d",&u,&v);
for(int i=; i<=n; ++i)
scanf("%d",&times[i]);
for(int i=; i<=m; ++i) {
scanf("%d%d",&t[i].si,&t[i].ti);
add(t[i].si,i); //将该点的初始时间与该点的编号进行连接
}
for(int i=; i<=n; ++i) {
if(i-times[i]>) //若往前找有可能能够观察到人
for(int j=head[i-times[i]],v; j; j=e[j].next) {
v=e[j].to; //能够成功被观察到的这个点的编号为v(通过链表进行寻找)
if(i<=t[v].ti) //是从v点往后找,所以v点的目的地必须要大于i才可以,不然走不到i点
ans[i]++;
}
if(i+times[i]<=n) { //若往后找有可能能够观察到人
for(int j=head[i+times[i]],v; j; j=e[j].next) {
v=e[j].to;
if(i>=t[v].ti) //同理,因为上一种情况是从v点往后找,所以v点的目的地必须大于i,这一种情况则相反(小于)
ans[i]++;
}
}
}
for(int i=; i<=n; ++i)
printf("%d ",ans[i]);
return ;
}
if(flag5) { //所有人的起点均相同,且为1
for(int i=,u,v; i<n; ++i) {
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
for(int i=; i<=n; ++i)
scanf("%d",&times[i]);
for(int i=,u,v; i<=m; ++i) {
scanf("%d%d",&u,&v);
sum[v]++;
}
bfs();
Dfs();
for(int i=; i<=n; ++i)
if(times[i]==deeps[i])
printf("%d ",son[i]);
else
printf("0 ");
}
return ;
}

②咦?正解呢?嘻嘻,还不会啦!


T3 换教室

直通

思路:

  这是一道概率DP的题

  首先我们用floyd求两教室间最短路,这个不用说,三个for循环即可

  然后我们可以用f[i,j,k] 表示前i个时间段申报j个。

  其中:k=0表示当前时间段没选,k=1表示当前时间段选了

上代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define INF 0x7fffffff
using namespace std; const int Mn = ;
const int Mv = ;
int n,m,v,e;
int c[Mn],d[Mn],map[Mv][Mv];
double ans=20020811.233,tmp;
double k[Mn],f[Mn][Mn][];
//f[i][j][k]表示前i个时间段申报j个.
//k=0表示当前时间段没选,k=1表示当前时间段选了 void pre() {
//这个初始化有点坑说实话...
memset(map,0x3f,sizeof(map));
for(int i=; i<Mv; ++i) map[i][i]=;
/*--------------------------------*/
for(int i=; i<Mn; ++i)
for(int j=; j<Mn; ++j)
f[i][j][]=f[i][j][]=INF;
} void floyd() {
for(int k=; k<=v; ++k)
for(int i=; i<=v; ++i)
for(int j=; j<=v; ++j)
if(map[i][k]+map[k][j]<map[i][j])
map[i][j]=map[i][k]+map[k][j];
} void dp() {
f[][][]=f[][][]=;
for(int i=; i<=n; ++i) { //从第二天开始换教室
for(int j=; j<=i && j<=m; ++j) { //开始dp选取换第几个教室
double tmp0=f[i][j][];
f[i][j][]=
min(f[i-][j][]+map[c[i-]][c[i]], //上一天不换并且今天也不换,所以直接加上两教室之间的距离(直接走过去)即可
f[i-][j][] //上一天换
+map[c[i-]][c[i]]*(1.0-k[i-]) //申报了但是申请不成功的概率
+map[d[i-]][c[i]]*k[i-]); //申报了并且申请成功的概率
f[i][j][]=min(tmp0,f[i][j][]); //跟没有更新之前的进行比较取最优值
if(j) { //如果能申报
double tmp1=f[i][j][];
f[i][j][]=
min(f[i-][j-][] //前i-1天申报j-1(因为当天已经确定申报)次
+k[i]*map[c[i-]][d[i]] //当天申报成功
+(1.0-k[i])*map[c[i-]][c[i]], //当天申报不成功
f[i-][j-][] //同上
+(1.0-k[i-])*k[i]*map[c[i-]][d[i]] //当天申报成功,上一天申报不成功
+k[i-]*k[i]*map[d[i-]][d[i]] //当天申报成功,上一天申报也成功
+k[i-]*(1.0-k[i])*map[d[i-]][c[i]] //当天申报不成功,上一天申报成功
+(1.0-k[i-])*(1.0-k[i])*map[c[i-]][c[i]] //当天申报不成功,上一天申报也不成功
);
f[i][j][]=min(f[i][j][],tmp1); //跟没有更新之前的进行比较取最优值
}
}
}
} int main() {
// freopen("classrooma.in","r",stdin);
// freopen("classrooma.out","w",stdout);
scanf("%d%d%d%d",&n,&m,&v,&e);
for(int i=; i<=n; ++i) scanf("%d",&c[i]);
for(int i=; i<=n; ++i) scanf("%d",&d[i]);
for(int i=; i<=n; ++i) scanf("%lf",&k[i]);
pre();
for(int i=,a,b,w; i<=e; ++i) {
scanf("%d%d%d",&a,&b,&w);
if(w<map[a][b]) map[a][b]=map[b][a]=w;
}
floyd();
dp();
for(int i=; i<=m; ++i)
tmp=min(f[n][i][],f[n][i][]),ans=min(ans,tmp);
printf("%.2lf\n",ans);
return ;
}

Noip2016 提高组 Day1的更多相关文章

  1. 【NOIP2016提高组day1】†换教室

    题目 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的 课程. 在可以选择的课程中,有 2n 节课程安排在 n 个时间段上. 在第 i ( 1 ≤ i ≤ n )个 时间段上,两 ...

  2. NOIP2016提高组解题报告

    NOIP2016提高组解题报告 更正:NOIP day1 T2天天爱跑步 解题思路见代码. NOIP2016代码整合

  3. 【题解】NOIP2016提高组 复赛

    [题解]NOIP2016提高组 复赛 传送门: 玩具谜题 \(\text{[P1563]}\) 天天爱跑步 \(\text{[P1600]}\) 换教室 \(\text{[P1850]}\) 组合数问 ...

  4. luogu1003铺地毯[noip2011 提高组 Day1 T1]

    题目描述 为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有 n 张地毯,编号从 1 到n .现在将这些地毯按照编号从小到大的顺序平行于 ...

  5. 18/9/9牛客网提高组Day1

    牛客网提高组Day1 T1 中位数 这好像是主席树??听说过,不会啊... 最后只打了个暴力,可能是n2logn? 只过了前30%  qwq #include<algorithm> #in ...

  6. Noip2011 提高组 Day1 T1 铺地毯 + Day2 T1 计算系数

    Day1 T1 题目描述 为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有 n 张地毯,编号从 1 到n .现在将这些地毯按照编号从小 ...

  7. Noip2011 提高组 Day1 T3 Mayan游戏

    题目描述 Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个 7 行5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上.游戏通关是指在规定 ...

  8. 【题解】NOIP2016 提高组 简要题解

    [题解]NOIP2016 提高组 简要题解 玩具迷题(送分) 用异或实现 //@winlere #include<iostream> #include<cstdio> #inc ...

  9. GZOJ 1361. 国王游戏【NOIP2012提高组DAY1】

    国王游戏[NOIP2012提高组DAY1] Time Limit:1000MS Memory Limit:128000K Description 国王游戏(game.cpp/c/pas) [问题描述] ...

随机推荐

  1. 阿里巴巴矢量图标库(iconfont)批量全选的方法

    阿里巴巴矢量图标库: https://www.iconfont.cn/ 浏览器打开调试面板,进入 console 调试面板(Google浏览器快捷键F12)或者在页面空白处,点击右键->审查元素 ...

  2. Python--类的调用

    类的调用 实例化 class Luffy: school = 'luffy' def __init__(self,name,age): self.Name = name self.Age = age ...

  3. java包装类的缓存机制(转)

    出处: java包装类的缓存机制 java 包装类的缓存机制,是在Java 5中引入的一个有助于节省内存.提高性能的功能,只有在自动装箱时有效 Integer包装类 举个栗子: Integer a = ...

  4. java 内部类、匿名内部类

    一:内部类 1:什么是内部类? 大部分时候,类被定义成一个独立的程序单元.在某些情况下,也会把一个类放在另一个类的内部定义,这个定义在其他类内部的类就被称为内部类(有些地方也叫做嵌套类),包含内部类的 ...

  5. 【AC自动机】洛谷三道模板题

    [题目链接] https://www.luogu.org/problem/P3808 [题意] 给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过. [题解] 不再介绍基础知识了,就是裸的模 ...

  6. Java 并发进阶常见面试题总结

    声明:本文内容完全来自网络,转自GitHub->JavaGuide(https://github.com/Snailclimb/JavaGuide),致谢      1. synchronize ...

  7. [转载]IMDB文件格式

    [转载]IMDB文件格式 来源:LMDB的全称是Lightning Memory-Mapped Database,闪电般的内存映射数据库.它文件结构简单,一个文件夹,里面一个数据文件,一个锁文件.数据 ...

  8. Batch normalization简析

    Batch normalization简析 What is batch normalization 资料来源:https://www.bilibili.com/video/av15997678/?p= ...

  9. base64转换成文件图片

    最近搞小程序分享画布遇到的坑 canvas drawImage 传入的第一个参数是 imageResource 图片资源路径,这个参数通常由从相册选择图片 wx.chooseImage 或 wx.ge ...

  10. Vue.prototype详解

    参考地址:Vue.prototype详解 如果需要设置 全局变量,在main.js中,Vue实例化的代码里添加. 不想污染全局作用域.这种情况下,你可以通过在 原型 上定义它们使其在每个Vue实例中可 ...