Problem A: 贪吃蛇

描述



Input



Output



Sample Input

【样例输入1】

4 5

##...

..1#@

432#.

...#.

【样例输出1】

4

【样例输入2】

4 4

#78#

.612

.543

..@.

【样例输出2】

6

【样例输入3】

3 2

3@

2#

1#

【样例输出3】

-1

这道题就是一个简单的广搜,储存蛇头位置,步数和蛇的身体的各个部分的位置。注意,要关照一下蛇不能越过自己的身体。

代码:


#include<bits/stdc++.h>
using namespace std;
struct zuobiao
{
int x,y;
}a[11];
struct data
{
int x,y,sum;
zuobiao number[10];
}b;
queue<data> q;
char ch;
int n,m,is[16][16],k,f[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
bool vis[16][16],flag;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>ch;
if(ch=='#')
{
is[i][j]=10;
}else{
if(ch=='@')
{
is[i][j]=11;
}else{
if(ch>='1'&&ch<='9')
{
k++;
b.number[ch-'0'].x=i;
b.number[ch-'0'].y=j;
if(ch=='1')
{
b.x=i;
b.y=j;
b.sum=0;
}
}
}
}
}
}
q.push(b);//放入队列
while(!q.empty())
{
data u=q.front();
data p=u;
q.pop();
for(int i=0;i<4;i++)
{
u=p;
int xx=u.number[1].x+f[i][0];
int yy=u.number[1].y+f[i][1];
int num=u.sum;
flag=0;
for(int i=1;i<k;i++)//可以咬尾巴,尾巴会走
{
if(xx==u.number[i].x&&yy==u.number[i].y)
{
flag=1;
break;
}
}
if(flag||is[xx][yy]==10||vis[xx][yy]||xx>n||xx<1||yy>m||yy<1)
{
continue;
}
if(is[xx][yy]==11)
{
printf("%d\n",num+1);
return 0;
}
for(int i=k;i>1;i--)//移动蛇身
{
u.number[i].x=u.number[i-1].x;
u.number[i].y=u.number[i-1].y;
}
u.sum++;
vis[u.number[1].x][u.number[1].y]=1;//更新
u.number[1].x=xx;
u.number[1].y=yy;
q.push(u);
}
}
puts("-1");//若无解
return 0;
}

Problem B: 字符串

UPD:本题字符集为全体小写字母

描述:



Input



Output



Sample Input

5
1 abc
3 abcabc
0 abc
3 aba
1 abababc

Sample Output

2
2

这一题题目描述明确地提示了一件事——本题是字符串题,虽然说了是强制在线,可能有点假,因为我们可以优化修改和查询的时间复杂度从而不理会强制在线带来的难题。

我们提前建好AC自动机的fail树记录好每个字符串的起始点,长度,并把它们合并到一起。 在fail树上的_a[s]_ 的值用线段树或者树状数组维护,dfs遍历打上时间戳。改修改的修改,该查询的查询,最后可以得出答案(某巨佬的想法)。

然后我说说个人有几个疑惑的点,为什么是这样做:

1.为什么可以用线段树或树状数组维护?

如图,点a的值加1,点b的值必定会加1。

2.这句话为什么?

add(dfn[num[i]]+size[num[i]],1);

很简单:



如果其中的4到6这个区间一起加了个1,在这个区间前和区间中的查找不会有什么影响,但区间后的一段就因为4到6加了个1,而被迫加了个1,所以我们在增加4到6区间时,也要相对应地在这个区间后减去1。

#include<bits/stdc++.h>
using namespace std;
int to[2000001],tot,nxt[2000001],head[2000001],len[2000001],cnt,num[2000001],dfn[2000001],indew,size[2000001],c[2000001],n,op[2000001],l,begi[2000001],mark;
char s[2000001],ch[2000001];
long long ans;
struct data
{
int b[26],fail;
}a[2000001];
void adde(int u,int v)
{
to[++tot]=v;
nxt[tot]=head[u];
head[u]=tot;
}
void build(char ch[],int id)
{
int root=0;
for(int i=0;i<len[id];i++)
{
int xx=ch[i]-'a';
if(!a[root].b[xx])
{
a[root].b[xx]=++cnt;
}
root=a[root].b[xx];
}
num[id]=root;
}
void fail()//建fail树
{
queue<int> q;
for(int i=0;i<26;i++)
{
if(a[0].b[i])
{
a[a[0].b[i]].fail=0;
q.push(a[0].b[i]);
}
}
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=0;i<26;i++)
{
if(a[u].b[i])
{
a[a[u].b[i]].fail=a[a[u].fail].b[i];
q.push(a[u].b[i]);
}else{
a[u].b[i]=a[a[u].fail].b[i];
}
}
}
for(int i=1;i<=cnt;i++)
{
adde(a[i].fail,i);
}
}
void dfs(int u)
{
dfn[u]=++indew;
size[u]=1;
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
dfs(v);
size[u]+=size[v];
}
}
int lowbit(int x)
{
return x&(-x);
}
void add(int x,int y)
{
for(;x<=indew;x+=lowbit(x))
{
c[x]+=y;
}
}
long long ask(int x)
{
int ans1=0;
for(;x;x-=lowbit(x))
{
ans1+=c[x];
}
return ans1;
}
void work(int l,int r)
{
long long root=0;
for(int i=l;i<=r;i++)
{
int xx=s[i]-'a';
root=a[root].b[xx];
ans+=ask(dfn[root]);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%s",&op[i],ch);
len[i]=strlen(ch);
begi[i]=l+1;
build(ch,i);
for(int j=0;j<len[i];j++)
{
s[++l]=ch[j];
}
}
fail();//建fail树
dfs(0);
for(int i=1;i<=n;i++)
{
op[i]^=mark;
if(op[i]==1)//树状数组
{
add(dfn[num[i]],1);
add(dfn[num[i]]+size[num[i]],-1);
}else{
if(op[i]==2)
{
add(dfn[num[i]],-1);
add(dfn[num[i]]+size[num[i]],1);
}else{
ans=0;
work(begi[i],begi[i]+len[i]-1);
printf("%lld\n",ans);
mark^=abs(ans);
}
}
}
return 0;
}

Problem C: 都城

题目描述:



Input



Output

看题好像很玄乎地样子,但是我们画出图来发现——以一个点为都城所形成的树上相邻两点的计划更改数相差1若a为b的father:ans[b]=ans[a]+1,反之则亦然

那我们可以根据这一点想到了树形DP,两遍dfs,第一遍确定以一个点为都城的ans值,第二遍通过上边这个式子推出所有点的ans。

#include<bits/stdc++.h>
using namespace std;
struct data
{
int y,fa;//记录原计划是x通往y还是y通往x是高速公路
};
vector<data> a[100001];
int ans[100001],n,x,y;
void dfs(int u,int fa)
{
for(int i=0;i<a[u].size();i++)
{
data v=a[u][i];
if(v.y==fa)
{
continue;
}
if(!v.fa)//求ans[1]
{
ans[1]++;
}
dfs(v.y,u);
}
}
void dfs1(int u,int fa)
{
for(int i=0;i<a[u].size();i++)
{
data v=a[u][i];
if(v.y==fa)
{
continue;
}
if(!v.fa)//计算
{
ans[v.y]=ans[u]-1;
}else{
ans[v.y]=ans[u]+1;
}
dfs1(v.y,u);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
a[x].push_back((data){
y,1
});
a[y].push_back((data){
x,0
});
}
dfs(1,-1);
dfs1(1,-1);
for(int i=1;i<=n;i++)
{
printf("%d\n",ans[i]);
}
return 0;
}

总结:

这次考的不太好,主要是第三题考场上没有注意到相邻两点的值相差1,只能打了一个暴搜。

题解和总结——noip2019集训测试赛(一)贪吃蛇+字符串+都城的更多相关文章

  1. noip2019集训测试赛(二十一)Problem B: 红蓝树

    noip2019集训测试赛(二十一)Problem B: 红蓝树 Description 有一棵N个点,顶点标号为1到N的树.N−1条边中的第i条边连接顶点ai和bi.每条边在初始时被染成蓝色.高桥君 ...

  2. noip2019集训测试赛(二十一)Problem A: Colorful Balls

    Problem A: Colorful Balls Description Snuke放了N个一排彩色的球.从左起第i个球的颜色是ci重量是wi她可以通过执行两种操作对这些球重新排序操作1:选择两个相 ...

  3. 【2016北京集训测试赛(十)】 Azelso (期望DP)

    Time Limit: 1000 ms   Memory Limit: 256 MB Description 题解 状态表示: 这题的状态表示有点难想...... 设$f_i$表示第$i$个事件经过之 ...

  4. 【2016北京集训测试赛(二)】 thr (树形DP)

    Description 题解 (这可是一道很早就碰到的练习题然后我不会做不想做,没想到在Contest碰到欲哭无泪......) 题目大意是寻找三点对的个数,使得其中的三个点两两距离都为d. 问题在于 ...

  5. 【2016北京集训测试赛(八)】 crash的数列 (思考题)

    Description 题解 题目说这是一个具有神奇特性的数列!这句话是非常有用的因为我们发现,如果套着这个数列的定义再从原数列引出一个新数列,它居然还是一样的...... 于是我们就想到了能不能用多 ...

  6. 【2016北京集训测试赛(十六)】 River (最大流)

    Description  Special Judge Hint 注意是全程不能经过两个相同的景点,并且一天的开始和结束不能用同样的交通方式. 题解 题目大意:给定两组点,每组有$n$个点,有若干条跨组 ...

  7. 【2016北京集训测试赛】river

    HINT 注意是全程不能经过两个相同的景点,并且一天的开始和结束不能用同样的交通方式. [吐槽] 嗯..看到这题的想法的话..先想到了每个点的度为2,然后就有点不知所措了 隐隐约约想到了网络流,但并没 ...

  8. 【2016北京集训测试赛】azelso

    [吐槽] 首先当然是要orzyww啦 以及orzyxq奇妙顺推很强qwq 嗯..怎么说呢虽然说之前零零散散做了一些概d的题目但是总感觉好像并没有弄得比较明白啊..(我的妈果然蒟蒻) 这题的话可以说是难 ...

  9. 2016北京集训测试赛(十七)Problem B: 银河战舰

    Solution 好题, 又是长链剖分2333 考虑怎么统计答案, 我场上的思路是统计以一个点作为结尾的最长上升链, 但这显然是很难处理的. 正解的方法是统计以每个点作为折弯点的最长上升链. 具体的内 ...

随机推荐

  1. 向net core 3.0进击——Swagger的改变

    目录 前言 引入 测试 小结 前言 十一小长假在不知不觉间可都没了,在这个小尾巴的空隙,把这两天鼓捣的net core 3.0升级过程记录一下,首先还是根据之前的顺序一个个补充进来,先从Swagger ...

  2. 设计模式----行为型模式之观察者模式(Observer Pattern)

    下面是阅读<Head First设计模式>的笔记. 观察者模式 定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新. JDK API内置机制 ...

  3. Windows内核编程时的习惯与注意事项

    Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html 一.内核编程注意细节: 在头文件中使用的是 <ntddk.h ...

  4. redis系列之------字典

    前言 字典, 又称符号表(symbol table).关联数组(associative array)或者映射(map), 是一种用于保存键值对(key-value pair)的抽象数据结构. 在字典中 ...

  5. js中的toString和valueOf

    数据的转换 基本上,所有JS数据类型都拥有valueOf和toString这两个方法,null除外.它们俩解决javascript值运算与显示的问题 所有对象继承了两个转换方法: 第一个是toStri ...

  6. deferred对象和promise对象(一)

    个人认为阮一峰老师讲的关于deferred对象是最容易理解的. deferred对象是jquery的回调函数解决方案.解决了如何处理耗时操作的问题,对那些操作提供了更好的控制,以及统一的编程接口. d ...

  7. JavaScript:如何获取某一天所在的星期

    我们会遇到的需求的是,获取今天或者某一天所在星期的开始和结束日期. 我们这里来获取今天所在星期的始末日期,我们可以通过(new Date).getDay()来获取今天是星期几,然后再通过这个减去或者加 ...

  8. golang 服务平滑重启小结

    背景 golang 程序平滑重启框架 supervisor 出现 defunct 原因 使用 master/worker 模式 背景 在业务快速增长中,前期只是验证模式是否可行,初期忽略程序发布重启带 ...

  9. js继承机制的实现

    js继承机制的实现 1. 继承的概念 说明继承的最经典的例子:几何形状.实际上,几何形状只有两种,即椭圆形(是圆形的)和多边形(具有一定数量的边).圆是椭圆的一种,它只有一个焦点.三角形.矩形和五边形 ...

  10. linux ln命令 建立文件夹桌面快捷方式

    指令如下: sudo ln -s /root/myhack/ /root/Desktop 以上指令是创建软链接到桌面. 指令解析: ln -s是创建软链接指令,如果不加-s则是创建硬链接.