yd的拔钉子之路之 POI 2017
写在前面的一些话
如果我NOIP没退役,这大概会写成一个系列吧,所以这算是系列的开始,要写一些奇怪的东西?
首先解释下什么叫“拔钉子”,其实就是在钉子上做题嘛......至于钉子具体是个什么东西就当面或者QQ问我好了=。=
然后如果写成系列的话前面这些应该都是POI了,那就说说POI好了。我个人还是很喜欢POI的出题风格的,基本上没有什么 Phantasm码农题/仙人板板板子题/很超巨大无比数据结构题(这都是什么啊喂(#`O′) )。思路在解题中比较重要,然后细节有时候也比较需要注意,至于码力这个东西在哪里都可以练......总的来说整体水平可以接受(至少有很多题是我这个马上NOIP退役的蒟蒻能做的),有一点就是经常出现智商题(2333)。当然也有一些很神仙的可能高于省选水平(?)的题,不过看到了可以绕着走就是了,反正只要有NOIP的水平应该都能找到一些可写的题的=。=
然后POI一年好像有17道题,似乎是一年考好几次试总起来的。国内的各个OJ基本上能覆盖掉POI 2016及以前的题,所以这些题在网上或多或少都能找到题解,之前应该也有好多dalao都按年份刷过POI的。不过不知道为什么POI2017只有BZOJ上Claris搬的五道题,剩下的国内OJ好像都没有......(但是为什么有POI2018的啊,钉子上都没有啊=。=)
好了,废话也说够了,开始写我的解题吧=。=
Round I
Flappy Bird
这题和 NOIP 2014 飞扬的小鸟 没有什么关系......
因为这只鸟只要擦过最后一对柱子就可以了,所以我们正着扫一遍,对每个柱子用它和上个柱子的间隔维护小鸟可以飞到的上下边界(上界是用来判无解的),然后这样一路维护到最后得到一个下界$minh$,答案就是$\left\lfloor \frac{x[n]+minh}{2} \right\rfloor$(点一下相当于可以飞两格,可以自己画画)。注意小鸟能飞到的点的横纵坐标之和一定是偶数,这个也需要维护一下=。=
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- using namespace std;
- long long n,x,t1,t2,t3,up,down,len,last;
- int main ()
- {
- scanf("%lld%lld",&n,&x);
- for(int i=;i<=n;i++)
- {
- scanf("%lld%lld%lld",&t1,&t2,&t3),len=t1-last;
- down=max(down-len,t2+),up=min(up+len,t3-);
- if((up-t1)&) up--; if((down-t1)&) down++;
- if(up<down) printf("NIE\n"),exit(); last=t1;
- }
- printf("%lld",(down+last)/);
- return ;
- }
Divisibility
首先有一个性质(其实我们小学可能都学过,雾):在B进制下一个数是B-1的倍数当且仅当其数位和是B-1的倍数
那么就很好做了,构造方法就是把所有数从大到小接起来,然后如果现在这个数不能整除被B-1整除就扣掉那个余数一位,这样剩余位数是最多的,数就是最大的,然后每个询问lower_bound一下就好了,注意边边角角的细节=。=
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- using namespace std;
- const int N=;
- long long b,q,k,res,tot,bit;
- long long cnt[N];
- int main ()
- {
- scanf("%lld%lld",&b,&q);
- for(int i=;i<b;i++)
- {
- scanf("%lld",&cnt[i]);
- tot+=cnt[i]*i,bit+=cnt[i];
- }
- res=tot%(b-);
- if(res) cnt[res]--,bit--;
- for(int i=;i<b;i++)
- cnt[i]+=cnt[i-];
- while(q--)
- {
- scanf("%lld",&k),k++;
- long long pos=lower_bound(cnt,cnt+b,k)-cnt;
- k<=cnt[b-]?printf("%lld\n",pos):printf("-1\n");
- }
- return ;
- }
Difference Representations
出现了,智商题!
虽然这题非常CF,不太像OI题=。=
发现这个数列每隔两个元素翻一番,所以一会就超过1e9(询问的最大值)了。那么我们暴力预处理前面的数直到它加爆1e9(注意一定是加爆才行),这说明奇数下标的元素和前面那个数的差值已经爆掉1e9了,那么再能凑出来一定是一个偶数下标的元素减去它前面那个元素。
先把预处理的数塞进map里,然后把预处理得到的所有数对的较大下标塞进一个数组$mem$里;对于每个询问先尝试在map里查一下,查不到就在$mem$里面二分出第一个小于它的位置$pos$,这样$pos$前面的都会被凑出来,而后面的就要两个两个每次加$1$来凑,所以设预处理出last个数后爆掉1e9了,那么对于一个数$x$的答案就是$(last+2*(x-pos),last+2*(x-pos)-1)$
- #include<map>
- #include<cstdio>
- #include<cstring>
- #include<utility>
- #include<algorithm>
- using namespace std;
- const int N=1e7+,MAXX=1e9;
- map<int,pair<int,int> > mp;
- map<int,pair<int,int> >::iterator it;
- int a[],mem[N],T,p,rd;
- void prework()
- {
- a[]=,a[p=]=,mp[]=make_pair(,);
- while(a[p]<=MAXX||p%==)
- {
- if((++p)&) a[p]=*a[p-];
- else
- for(int i=;i<=a[p-];i++)
- if(mp.find(i)==mp.end())
- {a[p]=a[p-]+i; break;}
- for(int i=;i<p;i++)
- mp[a[p]-a[i]]=make_pair(p,i);
- }
- for(it=mp.begin();it!=mp.end();it++)
- {
- pair<int,pair<int,int> > pr=*it;
- mem[++mem[]]=pr.first;
- }
- }
- int main ()
- {
- prework(),scanf("%d",&T);
- while(T--)
- {
- scanf("%d",&rd),it=mp.find(rd);
- if(it!=mp.end())
- {
- pair<int,pair<int,int> > pr=*it;
- printf("%d %d\n",pr.second.first,pr.second.second);
- }
- else
- {
- int pre=lower_bound(mem+,mem++mem[],rd)-mem-;
- printf("%d %d\n",p+*(rd-pre),p+*(rd-pre)-);
- }
- }
- return ;
- }
Sabotage
友善的二分答案+树形DP检验
好像挺简单的,设$dp[i]$表示最坏情况下$i$的子树里有几个叛徒,然后每次二分完DP一下就好了(雾
- #include<cstdio>
- #include<vector>
- #include<cstring>
- #include<algorithm>
- using namespace std;
- const int N=;
- const double eps=1e-;
- vector<int> son[N];
- int dp[N],siz[N];
- int n,k,rd,cnt;
- double l,r,mid;
- void DFS1(int nde)
- {
- siz[nde]=;
- for(int i=;i<(int)son[nde].size();i++)
- {
- int goal=son[nde][i]; DFS1(goal);
- siz[nde]+=siz[goal];
- }
- }
- void DFS2(int nde)
- {
- if(son[nde].empty())
- {dp[nde]=; return;}
- int maxx=;
- for(int i=;i<(int)son[nde].size();i++)
- {
- int goal=son[nde][i]; DFS2(goal);
- maxx=max(maxx,dp[goal]);
- }
- dp[nde]=((double)maxx/(double)(siz[nde]-)>mid)?siz[nde]:maxx;
- }
- bool check()
- {
- memset(dp,,sizeof dp),DFS2();
- return dp[]<=k;
- }
- int main()
- {
- scanf("%d%d",&n,&k);
- for(int i=;i<=n;i++)
- {
- scanf("%d",&rd);
- son[rd].push_back(i);
- }
- l=,r=,DFS1();
- while(r-l>eps)
- {
- mid=(l+r)/;
- check()?r=mid:l=mid;
- }
- printf("%lf",r);
- return ;
- }
Tourist
画风突变,做不来,告辞
求竞赛图的哈密顿回路,反正我是弃了,哪位神仙会做一定让我%1%
放个学长的链接吧=。=
Round 2
Sports competition
求一类特殊的二分图匹配的新思路(i207M说lyd讲过,我怎么不记得怕不是当时在摸鱼)
我们将每个左部点连到的右部点互相连起来并记录度数(只有一个右部点就连自己,度数加2),然后就得到了一个基环树森林。那么无解就是因为一棵基环树里的度数超过了点数的二倍,说明这个联通块里的边不够分了。判完无解之后我们就尝试把每棵基环树上的边定向来得到外向基环树,如果可行说明有唯一解;具体来说就是看看每个联通块里都有没有自环,如果有那么这棵基环树一定可以定向成一棵外向基环树,而没有的话就可能有两种定向,这样统计完如果有唯一解再DFS一遍即可得出方案。
- #include<cstdio>
- #include<vector>
- #include<cstring>
- #include<algorithm>
- using namespace std;
- const int N=1e6+;
- const long long mod=1e9+;
- int deg[N],sig[N],xnt[N],vis[N],cir[N],uni[N],outp[N];
- int p[N],noww[*N],goal[*N],val[*N];
- int n,t1,t2,pw,cnt,tot;
- vector<int> col[N];
- char rd[];
- void link(int f,int t,int v)
- {
- noww[++cnt]=p[f],p[f]=cnt;
- goal[cnt]=t,val[cnt]=v;
- }
- long long qpow(long long x,long long k)
- {
- if(k==) return x;
- long long tmp=qpow(x,k/);
- return k%?tmp*tmp%mod*x%mod:tmp*tmp%mod;
- }
- void DFS(int nde,int fth)
- {
- if(sig[nde]) uni[tot]=true;
- vis[nde]=true,col[tot].push_back(nde);
- for(int i=p[nde];i;i=noww[i])
- if(goal[i]!=fth)
- {
- if(vis[goal[i]]) cir[tot]=goal[i];
- else DFS(goal[i],nde);
- }
- }
- void mark(int nde,int fth)
- {
- vis[nde]=true;
- for(int i=p[nde];i;i=noww[i])
- if(goal[i]!=fth)
- {
- outp[val[i]]=goal[i];
- if(!vis[goal[i]]) mark(goal[i],nde);
- }
- }
- int main()
- {
- scanf("%d",&n);
- for(int i=;i<=n;i++)
- {
- scanf("%s",rd);
- if(rd[]=='T')
- {
- scanf("%d",&t1),sig[t1]=true;
- link(t1,t1,i),deg[t1]+=;
- }
- else
- {
- scanf("%d%d",&t1,&t2);
- link(t1,t2,i),link(t2,t1,i);
- deg[t1]++,deg[t2]++;
- }
- }
- for(int i=;i<=n;i++)
- if(!vis[i]) tot++,DFS(i,-);
- for(int i=;i<=tot;i++)
- for(int j=;j<(int)col[i].size();j++)
- xnt[i]+=deg[col[i][j]];
- for(int i=;i<=tot;i++)
- {
- if(xnt[i]>*(int)col[i].size())
- printf("NIE\n0"),exit();
- if(!uni[i]) pw++;
- }
- if(pw) printf("NIE\n%lld",qpow(,pw)),exit();
- memset(vis,,sizeof vis);
- for(int i=;i<=tot;i++)
- mark(cir[i],-);
- printf("TAK\n");
- for(int i=;i<=n;i++)
- printf("%d\n",outp[i]);
- return ;
- }
Sum of digits
惊了,CF怕不是出了个POI原题弱化版
这就是CF1070A Find a number的加强版,现在询问数位和为$s$且能被$d$整除的第$k$小数(原题询问最小的数),当然数据范围也减少了不少
然后我咕了,做法应该差不多吧
Strike
又出现了,智商题!
一开始把题想复杂了,问ztb他说可以用线段树维护BFS序(不过这也算学到了,我以前从没想过这种东西233),结果后来又发现好像维护不了。然后i207M说他要写写试试,过了一会他告诉我他A了,根本不用线段树,直接模拟即可=。=
对每个点记录它是否存在和它有几个儿子还存在,然后记录当前点数和边数按题意模拟即可,每次答案即点数-边数,注意根节点特殊考虑一下
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- using namespace std;
- const int N=;
- int exi[N],anc[N],son[N];
- int p[N],noww[*N],goal[*N];
- int n,T,t1,t2,rd,cnt,cnn,cne,root;
- void link(int f,int t)
- {
- noww[++cnt]=p[f];
- goal[cnt]=t,p[f]=cnt;
- }
- void DFS(int nde,int fth)
- {
- anc[nde]=fth,exi[nde]=true;
- for(int i=p[nde];i;i=noww[i])
- if(goal[i]!=fth) DFS(goal[i],nde),son[nde]++;
- }
- int main ()
- {
- scanf("%d",&n);
- for(int i=;i<n;i++)
- {
- scanf("%d%d",&t1,&t2);
- link(t1,t2),link(t2,t1);
- }
- cnn=n,cne=n-,root=;
- DFS(,),scanf("%d",&T);
- while(T--)
- {
- scanf("%d",&rd);
- if(rd>)
- {
- exi[rd]=false,cnn--,cne-=son[rd];
- if(rd!=root)
- {
- son[anc[rd]]--;
- if(exi[anc[rd]]) cne--;
- }
- }
- else
- {
- rd=-rd;
- exi[rd]=true,cnn++,cne+=son[rd];
- if(rd!=root)
- {
- son[anc[rd]]++;
- if(exi[anc[rd]]) cne++;
- }
- }
- printf("%d\n",cnn-cne);
- }
- return ;
- }
Shipping containers
纪念在钉子上的第一个Unaccepted(Runtime Error),因为没判断越界的问题=。=
根号分类讨论来均摊复杂度,对于距离$d$小于$sqrt(n)$的以$d$为间隔差分一下最后求前缀和,对于距离大于$sprt(n)$的直接暴力做,总复杂度$O(n$ $sqrt(n))$。注意空间可能比较紧,可以把标准调的小于根号$n$一些(钉子是按点测试而且大测试点基本都有3~4s,所以基本不会卡常)
- #pragma GCC optimize(2)
- #include<cmath>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- using namespace std;
- const int N=,Sqrt=;
- int dif[Sqrt][N],num[N];
- int n,m,t1,t2,t3,ed,blo;
- int main ()
- {
- scanf("%d%d",&n,&m),blo=min(,(int)sqrt(n));
- for(int i=;i<=m;i++)
- {
- scanf("%d%d%d",&t1,&t2,&t3),ed=t1+(t2-)*t3;
- if(t3<=blo)
- {
- dif[t3][t1]++;
- if(ed+t3<=n) dif[t3][ed+t3]--;
- }
- else
- for(int i=t1;i<=ed;i+=t3) num[i]++;
- }
- for(int i=;i<=blo;i++)
- for(int j=;j<=n;j++)
- {
- if(j-i>=)
- dif[i][j]+=dif[i][j-i];
- num[j]+=dif[i][j];
- }
- for(int i=;i<=n;i++)
- printf("%d ",num[i]);
- return ;
- }
Pizza delivery
哇蒟蒻博主发现自己并没有按年份刷的实力和时间,于是......
咕咕咕飞走
如果这只鶸NOIP没退役他大概会回来补的,这之前大概POI的解题还得散着写=。=
yd的拔钉子之路之 POI 2017的更多相关文章
- BZOJ 4726 POI 2017 Sabota? 树形DP
4726: [POI2017]Sabota? Time Limit: 20 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 128 Solved ...
- [ POI 2017 ] Sabota?
Description 题目链接 Solution 因为一个节点染黑了子树就都被染黑了,所以最后染黑的点集必然是一棵子树. 可以得出的结论是,如果被染黑的节点在节点 \(a\) 的子树中,而 \(a\ ...
- [ POI 2017 ] Podzielno
\(\\\) \(Description\) \(B\)进制数,每个数字\(i(i\in [0,B-1])\)有\(A_i\)个.用这些数字组成一个最大的\(B\)进制数\(X\)(不能有前导零,不需 ...
- QDUOJ ycb的ACM进阶之路 二进制多重背包
ycb的ACM进阶之路 发布时间: 2017年5月22日 14:30 最后更新: 2017年5月22日 14:31 时间限制: 1000ms 内存限制: 128M 描述 ycb是个天资聪颖 ...
- 利用Crowbar抓取网页异步加载的内容 [Python俱乐部]
利用Crowbar抓取网页异步加载的内容 [Python俱乐部] 利用Crowbar抓取网页异步加载的内容 在做 Web 信息提取.数据挖掘的过程中,一个关键步骤就是网页源代码的获取.但是出于各种原因 ...
- 设计模式总结(《Head First设计模式》学习总结)
写在前面: 学习过程中不仅要熟练掌握技能,理论的消化吸收也必不可少.虽然个人更倾向于学习技术类的东西(短时间的精力投入很快就能看到成效...),但看了很多前辈的经验总结后才知道理论性的东西是绝对不能忽 ...
- 借助Python来实现的定量城市研究
一.数据处理基础 (一)数据分析的概念 城市数据分析,可以从数据分析的广义和狭义两个角度来看: 狭义的数据分析是指根据分析目的,采用对比分析.分组分析.交叉分析和回归分析等分析方法,对相关城市数据(包 ...
- 基于bert_bilstm_crf的命名实体
前言 本文将介绍基于pytorch的bert_bilstm_crf进行命名实体识别,涵盖多个数据集.命名实体识别指的是从文本中提取出想要的实体,本文使用的标注方式是BIOES,例如,对于文本虞兔良先生 ...
- 如何一秒钟从头构建一个 ASP.NET Core 中间件
前言 其实地上本没有路,走的人多了,也便成了路. -- 鲁迅 就像上面鲁迅说的那样,其实在我们开发中间件的过程中,微软并没有制定一些策略或者文档来约束你如何编写一个中间件程序, 但是其中却存在者一些最 ...
随机推荐
- MantisBT导出Excel文件名显示中文的修改方法
我安装的是 mantisbt-2.15.0. 在“查看问题”页面导出Excel文件后,其文件名虽然是我选择的项目名称,但是,若项目名称中有中文,这就是用%加编码显示. 解决方法是: 在 <Ma ...
- Unity中几个特殊路径在各个平台的访问方式
1.文件路径Resources:Unity在发布成移动端项目后,其他文件路径都将不存在,但是如果有一些必要的资源,可以放在Resources文件夹下,因为这个文件夹下的所有资源是由Unity内部进行调 ...
- web _service 接口
1.WebService 就是 http请求 post接口 2.需要加 请求头信息 Content-Type: text/xml; 3.需要把占位符换成需要的字符串 webservice接口可以 ...
- 3星|麦肯锡合伙人《从1到N》:PPT讲稿,图表不错,讲解不够深入
从1到N:企业数字化生存指南 两位作者是麦肯锡合伙人.全书插图比较多,图做的还比较有水平.但是相关文字不够深入,我读后的感觉是:图表不是两位执笔者做的,他们对细节不清楚,对图表涉及到的行业也缺乏深入的 ...
- tensorflow中使用mnist数据集训练全连接神经网络-学习笔记
tensorflow中使用mnist数据集训练全连接神经网络 ——学习曹健老师“人工智能实践:tensorflow笔记”的学习笔记, 感谢曹老师 前期准备:mnist数据集下载,并存入data目录: ...
- Paper Reading - Sequence to Sequence Learning with Neural Networks ( NIPS 2014 )
Link of the Paper: https://arxiv.org/pdf/1409.3215.pdf Main Points: Encoder-Decoder Model: Input seq ...
- 深度系统(deepin)与win10双系统切换设置
之前在win10下安装了深度系统,我不知道其他人在双系统切换的时候是否需要更改BIOS参数,我根据我的实际情况给出双系统切换设置的解决方案. 1.开机后进入选项System setup 2.按照下图选 ...
- ASP.NET MVC5 学习系列之表单和HTML辅助方法
一.表单 (一)Action和Method特性 Action特性用以告知浏览器信息发往何处,因此,Action特性后面需要包含一个Url地址.这里的Url地址可以是相对的,也可以是绝对的.如下Form ...
- paoding rose controller包及文件名命名规则
1.包命名规则:xxx.xxx.controllers(否则扫描不到)
- application/x-www-form-urlencoded 与 application/json区别
两种请求方式对服务器端都没什么影响 application/x-www-form-urlencoded方式是比较老的一种方式,这种方式的好处就是浏览器都支持, 在请求发送过程中会对数据进行序列化处理, ...