写在前面的一些话

如果我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的更多相关文章

  1. BZOJ 4726 POI 2017 Sabota? 树形DP

    4726: [POI2017]Sabota? Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 128  Solved ...

  2. [ POI 2017 ] Sabota?

    Description 题目链接 Solution 因为一个节点染黑了子树就都被染黑了,所以最后染黑的点集必然是一棵子树. 可以得出的结论是,如果被染黑的节点在节点 \(a\) 的子树中,而 \(a\ ...

  3. [ POI 2017 ] Podzielno

    \(\\\) \(Description\) \(B\)进制数,每个数字\(i(i\in [0,B-1])\)有\(A_i\)个.用这些数字组成一个最大的\(B\)进制数\(X\)(不能有前导零,不需 ...

  4. QDUOJ ycb的ACM进阶之路 二进制多重背包

    ycb的ACM进阶之路 发布时间: 2017年5月22日 14:30   最后更新: 2017年5月22日 14:31   时间限制: 1000ms   内存限制: 128M 描述 ycb是个天资聪颖 ...

  5. 利用Crowbar抓取网页异步加载的内容 [Python俱乐部]

    利用Crowbar抓取网页异步加载的内容 [Python俱乐部] 利用Crowbar抓取网页异步加载的内容 在做 Web 信息提取.数据挖掘的过程中,一个关键步骤就是网页源代码的获取.但是出于各种原因 ...

  6. 设计模式总结(《Head First设计模式》学习总结)

    写在前面: 学习过程中不仅要熟练掌握技能,理论的消化吸收也必不可少.虽然个人更倾向于学习技术类的东西(短时间的精力投入很快就能看到成效...),但看了很多前辈的经验总结后才知道理论性的东西是绝对不能忽 ...

  7. 借助Python来实现的定量城市研究

    一.数据处理基础 (一)数据分析的概念 城市数据分析,可以从数据分析的广义和狭义两个角度来看: 狭义的数据分析是指根据分析目的,采用对比分析.分组分析.交叉分析和回归分析等分析方法,对相关城市数据(包 ...

  8. 基于bert_bilstm_crf的命名实体

    前言 本文将介绍基于pytorch的bert_bilstm_crf进行命名实体识别,涵盖多个数据集.命名实体识别指的是从文本中提取出想要的实体,本文使用的标注方式是BIOES,例如,对于文本虞兔良先生 ...

  9. 如何一秒钟从头构建一个 ASP.NET Core 中间件

    前言 其实地上本没有路,走的人多了,也便成了路. -- 鲁迅 就像上面鲁迅说的那样,其实在我们开发中间件的过程中,微软并没有制定一些策略或者文档来约束你如何编写一个中间件程序, 但是其中却存在者一些最 ...

随机推荐

  1. Linux目录与文件操作

    文件命名规则: 1.严格区分大小写: 2.长度不能超过255个字符: 3.不能使用/当文件名 mkdir:创建空目录 -p:parent,父目录,逐级创建 -v:verbose,打印详细信息 命令行展 ...

  2. No.03---Vue学习之路之模块化组织

    前两篇讲解了一下 Vuex 的基本使用方法,可是在实际项目中那么写肯定是不合理的,如果组件太多,不可能把所有组件的数据都放到一个 store.js 中的,所以就需要模块化的组织 Vuex,首先看一下 ...

  3. 【snmp】Linux开启snmp及查询

    1.Linux snmp 1.安装snmp yum install -y net-snmp* 2.备份snmp配置 cp /etc/snmp/snmpd.conf /etc/snmp/snmpd.co ...

  4. java使用jacob将office文档转换为PDF格式

    jacob 包下载地址: http://sourceforge.net/projects/jacob-project/ 下载后,将jacob 与 jacob-1.19-x64.dll放到安装jdk目录 ...

  5. .net mvc5 不同view()的视图 代码

    public class Test { public int id { set; get; } public string name { set; get; } } public ActionResu ...

  6. 算法笔记(c++)--关于01背包的滚动数组

    算法笔记(c++)--关于01背包的滚动数组 关于01背包问题:基本方法我这篇写过了. https://www.cnblogs.com/DJC-BLOG/p/9416799.html 但是这里数组是N ...

  7. gopherjs

    An example implementation of a GopherJS client and a Go server using the Improbable gRPC-Web impleme ...

  8. ViewPort <meta>标记

    ViewPort <meta>标记用于指定用户是否可以缩放Web页面,如果可以,那么缩放到的最大和最小缩放比例是什么.使用ViewPort <meta>标记还表示文档针对移动设 ...

  9. 寻找bug

    bug1:void不应有返回值. bug2:while(n--)没有条件终止循环. bug3:size和data没有定义 bug4:arr 是sz 在大于0的情况下创建的 一定部位bull   下面的 ...

  10. 《linux内核分析》 第一周

    20135130  王川东 计算机是如何工作的? 计算机的基本原理是存储程序和程序控制.预先要把指挥计算机如何进行操作的指令序列(称为程序)和原始数据通过输入设备输送到计算机内存贮器中.每一条指令中明 ...