题解和总结——noip2019集训测试赛(一)贪吃蛇+字符串+都城
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集训测试赛(一)贪吃蛇+字符串+都城的更多相关文章
- noip2019集训测试赛(二十一)Problem B: 红蓝树
noip2019集训测试赛(二十一)Problem B: 红蓝树 Description 有一棵N个点,顶点标号为1到N的树.N−1条边中的第i条边连接顶点ai和bi.每条边在初始时被染成蓝色.高桥君 ...
- noip2019集训测试赛(二十一)Problem A: Colorful Balls
Problem A: Colorful Balls Description Snuke放了N个一排彩色的球.从左起第i个球的颜色是ci重量是wi她可以通过执行两种操作对这些球重新排序操作1:选择两个相 ...
- 【2016北京集训测试赛(十)】 Azelso (期望DP)
Time Limit: 1000 ms Memory Limit: 256 MB Description 题解 状态表示: 这题的状态表示有点难想...... 设$f_i$表示第$i$个事件经过之 ...
- 【2016北京集训测试赛(二)】 thr (树形DP)
Description 题解 (这可是一道很早就碰到的练习题然后我不会做不想做,没想到在Contest碰到欲哭无泪......) 题目大意是寻找三点对的个数,使得其中的三个点两两距离都为d. 问题在于 ...
- 【2016北京集训测试赛(八)】 crash的数列 (思考题)
Description 题解 题目说这是一个具有神奇特性的数列!这句话是非常有用的因为我们发现,如果套着这个数列的定义再从原数列引出一个新数列,它居然还是一样的...... 于是我们就想到了能不能用多 ...
- 【2016北京集训测试赛(十六)】 River (最大流)
Description Special Judge Hint 注意是全程不能经过两个相同的景点,并且一天的开始和结束不能用同样的交通方式. 题解 题目大意:给定两组点,每组有$n$个点,有若干条跨组 ...
- 【2016北京集训测试赛】river
HINT 注意是全程不能经过两个相同的景点,并且一天的开始和结束不能用同样的交通方式. [吐槽] 嗯..看到这题的想法的话..先想到了每个点的度为2,然后就有点不知所措了 隐隐约约想到了网络流,但并没 ...
- 【2016北京集训测试赛】azelso
[吐槽] 首先当然是要orzyww啦 以及orzyxq奇妙顺推很强qwq 嗯..怎么说呢虽然说之前零零散散做了一些概d的题目但是总感觉好像并没有弄得比较明白啊..(我的妈果然蒟蒻) 这题的话可以说是难 ...
- 2016北京集训测试赛(十七)Problem B: 银河战舰
Solution 好题, 又是长链剖分2333 考虑怎么统计答案, 我场上的思路是统计以一个点作为结尾的最长上升链, 但这显然是很难处理的. 正解的方法是统计以每个点作为折弯点的最长上升链. 具体的内 ...
随机推荐
- windows下 python 如何安装pygame模块
本机系统:win7,Pyhon版本: 3.6.0 1. 安装下载python官网 https://www.python.org/ 下载地址 https://www.python.org/downloa ...
- ueditor的初始化赋值
ue.ready(function () {ue.setContent('初始内容'); //赋值给UEditor });
- Vim 使用 DrawIt 画图
简介 DrawIt 插件用来在 Vim 中进行简单的画图功能.可以方便地移动光标并画出横线.竖线.斜线.箭头和交叉字符,也带有实用的画图功能,轻松画带箭头的线.矩形及椭圆. 官方主页:https:// ...
- Android的各大框架整理
OpenDanmaku :一个Android的弹幕控件 地址:https://github.com/linsea/OpenDanmaku AndroidViewAnimations:Andorid视 ...
- docker相关概念介绍
关键词:docker容器与docker镜像 他们之间的关系是docker容器通过docker镜像来创建 docker镜像就是些像ubuntu15.10,ubuntu14.2一样的系统 docker容器 ...
- 防止CSRF跨站请求伪造
CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站 ...
- 全面认识nslookup命令及子命令
- Kafka源码研究--Comsumer获取partition下标
背景 由于项目上Flink在设置parallel多于1的情况下,job没法正确地获取watermark,所以周末来研究一下一部分,大概已经锁定了原因: 虽然我们的topic只设置了1的partitio ...
- ESP8266开发之旅 网络篇⑨ HttpClient——ESP8266HTTPClient库的使用
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- 使用Jersey构建图片服务器
使用Jersey构建图片服务器 前台页面代码 <form id="jvForm" action="add.do" method="post&qu ...