这场比赛的题是大约一个月前出的,当时刚从NOIP2001-NOIP2011之间的题目比较顺利地走过来。当时感觉NOIP并不是很难,但在这一个月经历了很多,最近几年的NOIP瞬间让我意识到自己能力的不足,特别是在NOIP2012,NOIP2015中惨败,又见识了起步早,能力强的小学/初中大佬,这让学了15个月OI马上要参加最后一次NOIP的我倍感压力。
从近年NOIP的考试趋势来看,部分考察知识开始涉及省选或以前不常考内容,题目难度也有所上升。现在看这套题,我觉得题目风格偏旧,难度不足,有点像NOIP2011之前的考试风格。总之,有诸多不足,望见谅。如果有误,请指出。
比赛链接:https://www.luogu.org/contestnew/show/10364
数据下载:https://share.weiyun.com/5HFfVLB
密码:noip (注意:T1#10,T2#4,T3#4有bug)
注:关于下面引理的证明,我第一次了解是在某数学竞赛黑皮书上
考察知识:数学,数论,模拟
算法难度:XX+ 实现难度:X
评价:这还是算一道和NOIP切和很好的题目,数学类题目是近年NOIP必考题。
感想:我本来以为然而
分析:
这道题用类似高精度除法的方法可以做,但是肯定要超时。
正解和NOIP2017T1解法有点相似,也是推(cai)结(da)论(an)的题
坑点:如果不先取模再乘会爆 long long
证明:
先证明一个引理:对于数
注意到: 则 ,
引理得证。
我们已经离结论很近了,如果我们单纯把 的数字进行分解还是要超时,所以我们还要继续优化:
结论得证。
注:背景来自某小说,有趣的是,今天(9.21)我在洛谷上看到了另一道题目背景相同的题(当然,只是题目背景相同),有兴趣可以看看:CF173B Chamber of Secrets
考察知识:图的最短路
算法难度:XX+ 实现难度:XXX
评价:非常常规,主要考察最短路的求法
感想:哎,出得太简单了,但是需要大家读懂题
分析:
没什么好分析的,用多次最短路+分类讨论就可以了。
情况一:哈利罗恩分别去一间密室
情况二:哈利一个人去两间密室
注:游戏规则改编自游戏:slither.io
注意:对于部分数据(有蛇连在一起)我的代码可能会错误
忠告:模拟类题目(比如:侦探推理,mayan游戏)在NOIP还是经常考到的,而且描述大多也不是非常清晰,所以大家要仔细读题,自己推敲。
考察知识:模拟,队列,四连块搜索
算法难度:XXX+ 实现难度:XXX+
评价:如果数据强度够大,如果放到NOIP2011年以前,也可能算最后一道题的难度了,现在的话......
感想:好吧,也许题目描述确实有点杂乱,但是我说过数据很水。
分析:
注意题目数据范围中的限制:100%数据满足,n,m<=200,c<=20,k<=100,且图中的蛇不会引起混淆
首先题目数据范围很小,我们直接按要求模拟就可以了,其次蛇不会引起混淆,我们就可以用dfs标记每条蛇身的顺序,就可以模拟出蛇的移动了。
细节:
1.蛇身的储存:用队列实现,先dfs搜索将蛇加入队列:队首为蛇尾,队尾为蛇头
2.蛇的移动:队首出队列,将蛇头到达的地方加入队列
3.蛇的死亡:因为蛇为四连块,用dfs标记
4.其他细节见代码
附,数据可能存在(两条蛇不会混淆吧):
......
..@@..
......
但数据不会这么坑:
.#.
##@
#.#
@##
T1:
#include
using namespace std;
long long Q,l,r,a,b;
int main(){
cin>>Q;
while(Q--){
cin>>l>>r;
a=r-l+1,b=l+r;//等差数列求和公式
if(a%2==0) a/=2;
else b/=2;
a%=9,b%=9;//分开求防止爆long long
cout<<(a*b)%9<<'\n';
}
return 0;
}
T2:
#include
#include
#include
#include
#include
using namespace std;
const int maxn=100005,maxm=500005;
struct node{
int id,d;
friend bool operator < (node A,node B){
return A.d>B.d;
}
};
struct edge{
int to,next,c;
}e[maxm*2];
int head[maxn],np;
void add(int u,int v,int c){
e[++np]=(edge){v,head[u],c};
head[u]=np;
e[++np]=(edge){u,head[v],c};
head[v]=np;
}
bool vis[maxn];
int n,m,k,x,y,locked[maxn];
int d1[maxn],d2[maxn],d3[maxn];
//d1[i]:哈利由1到i的最短路
//d2[i]:罗恩由1到i的最短路
//d3[y]:哈利由x到y的最短路
void dijstra(int s,int* d,bool Access){
priority_queuepq;
memset(vis,0,sizeof(vis));
d[s]=0;
pq.push((node){s,0});
int i;
while(!pq.empty()){
i=pq.top().id;pq.pop();
if(vis[i]) continue;
vis[i]=true;
for(int p=head[i];p;p=e[p].next){
int j=e[p].to;
if(!Access&&locked[j]) continue;
if(d[i]+e[p].c
T3:
#include
#include
#include
#include
#include
using namespace std;
struct P{
int x,y;
};
queuebody[25];//储存蛇身
struct snake{//储存分数,id
int id,len;
bool operator < (const snake& B){
return len>B.len||(len==B.len&&idn||j>m) return true;
return false;
}
void print(){//仅用于查看中间结果
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
if(mp[i][j]>0) printf("%d",mp[i][j]);
else putchar(mp[i][j]?'&':'.');
putchar('\n');
}
putchar('\n');
}
void dfs(int i,int j,int id_){//四连块搜索蛇身
if(!mp[i][j]&&(a[i][j]=='#'||(a[i][j]=='@'&&len[id_]==0)))
mp[i][j]=id_,len[id_]++;
else return;
for(int ii=0;ii<4;ii++)
dfs(i+dx[ii],j+dy[ii],id_);
body[id_].push((P){i,j});//队列维护贪吃蛇蛇身
}
void die(int id_){//贪吃蛇死亡
len[id_]=0;
while(!body[id_].empty()){
P T=body[id_].front();
body[id_].pop();
mp[T.x][T.y]=-1;//变成食物
}
}
void move(int i,int j,int id_,int case_){//贪吃蛇移动
int i_=i+dx[case_],j_=j+dy[case_];
if(mp[i_][j_]>0||not_in(i_,j_)) die(id_);//撞到边界或蛇导致死亡
else if(mp[i_][j_]==-1){//吃到食物
len[id_]++,mp[i_][j_]=id_;
head[id_][0]=i_,head[id_][1]=j_;
body[id_].push((P){i_,j_});
}
else{//移动一步
mp[i_][j_]=id_,head[id_][0]=i_,head[id_][1]=j_;
body[id_].push((P){i_,j_});
P T=body[id_].front();
body[id_].pop();
mp[T.x][T.y]=0;
}
}
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>a[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a[i][j]=='@')//放心大胆的四连块搜索
dfs(i,j,++id),head[id][0]=i,head[id][1]=j;
else if(a[i][j]=='&')
mp[i][j]=-1;
for(int i=1;i<=id;i++) scanf("%s",cmd[i]);
for(int i=0;i0){//如果蛇没有死才移动
switch(cmd[i_][i]){//注意操作与dx[],dy[]的对应关系
case 'W':move(head[i_][0],head[i_][1],i_,3);break;
case 'A':move(head[i_][0],head[i_][1],i_,1);break;
case 'S':move(head[i_][0],head[i_][1],i_,0);break;
case 'D':move(head[i_][0],head[i_][1],i_,2);break;
}
}
// print(); /*查看中间结果*/
}
for(int i=1;i<=id;i++)
s[i].id=i,s[i].len=len[i];
sort(s+1,s+id+1);
for(int i=1;i<=id;i++) printf("%d %d\n",s[i].len,s[i].id);
int cnt=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(mp[i][j]==-1) cnt++;
printf("%d",cnt);
return 0;
}
总结:答疑好累呀(-_-||),我现在头晕眼花(-_-||),看了一下别人举办的比赛,大部分难度都比较大,如果我要举办模拟赛DAY2,那么一定会加大难度。