【题解】NOIP2016 提高组 简要题解

玩具迷题(送分)

用异或实现

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm> using namespace std; typedef long long ll;
inline int qr(){
register int ret=0,f=0;
register char c=getchar();
while(!isdigit(c))f|=c==45,c=getchar();
while(isdigit(c)) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
} const int maxn=1e5+5;
int n,m;
string data[maxn];
bool f[maxn];
int main(){
n=qr(); m=qr();
for(int t=0;t<n;++t)
f[t]=qr(),cin>>data[t];
int now=0;
for(int t=1,t1,t2;t<=m;++t){
t1=qr(); t2=qr();
if(t1^f[now]) now=(now+t2)%n;
else now=(now-t2+n)%n;
}
cout<<data[now]<<endl;
return 0;
}

天天爱跑步(树上差分)

树上路径问题常见套路

将一个人从起点到终点的路径上从\(0\)开始编号,可以发现这个路径被分为三段:

  • 编号随着深度递减而递增。
  • LCA
  • 编号随着深度递增而递增。

分别维护两个\(d[u]+-w[u]\)的桶即可。

但是还没有保证只有路径上的点才可能看到这个跑步者,所以直接差分一下即可。

注意到此类路径影响点并且要差分的问题一定要单独处理LCA

瓶颈在\(LCA\),换成\(tarjan\)就\(O(n)\)了

//@winlere
#include<tr1/unordered_map>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector> using namespace std; using namespace std::tr1; typedef long long ll;
typedef vector<int>::iterator Vint;
typedef unordered_map<int,int>::iterator Uint; inline int qr(){
register int ret=0,f=0;
register char c=getchar();
while(!isdigit(c))f|=c==45,c=getchar();
while(isdigit(c)) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
} const int maxn=3e5+1;
struct E{int k,val;};
vector<E> q1[maxn],q2[maxn];
typedef vector<E>::iterator Pint;
vector<int> e[maxn];
inline void add(const int&fr,const int&to){
e[fr].push_back(to);
e[to].push_back(fr);
}
int n,m,w[maxn],d[maxn],top[maxn],siz[maxn],son[maxn],r[maxn],ans[maxn],cnt[maxn]; namespace pre{
void dfs(const int&now,const int&last){
d[now]=d[r[now]=last]+1;
siz[now]=1;
for(Vint t=e[now].begin();t!=e[now].end();++t)
if(*t^last) dfs(*t,now),son[now]=siz[*t]>siz[son[now]]?*t:son[now],siz[now]+=siz[*t];
}
void dfs2(const int&now,const int&last){
top[now]=last;
if(son[now])dfs2(son[now],last);
for(Vint t=e[now].begin();t!=e[now].end();++t)
if((*t^r[now])&&(*t^son[now]))
dfs2(*t,*t);
}
inline int lca(int u,int v){
for(;top[u]^top[v];u=r[top[u]])
if(d[top[u]]<d[top[v]]) swap(u,v);
return d[u]>d[v]?v:u;
}
inline void init(){dfs(1,0); dfs2(1,1);}
} struct D{
unordered_map<int,int> s;
D(){s.clear();}
inline void upd(const int&pos,const int&tag){s[pos]+=tag;}
inline int que(const int&pos){Uint g=s.find(pos);return g==s.end()?0:g->second;}
}s1,s2; void solve(const int&now,const int&last){
ans[now]-=s1.que(d[now]+w[now])+s2.que(d[now]-w[now]);
for(Vint t=e[now].begin();t!=e[now].end();++t) if(*t^last) solve(*t,now);
for(Pint t=q1[now].begin();t!=q1[now].end();++t) s1.upd(t->k,t->val);
for(Pint t=q2[now].begin();t!=q2[now].end();++t) s2.upd(t->k,t->val);
ans[now]+=s1.que(d[now]+w[now])+s2.que(d[now]-w[now]);
} int main(){
n=qr(); m=qr();
for(int t=1;t<n;++t) add(qr(),qr());
for(int t=1;t<=n;++t) w[t]=qr();
pre::init();
for(int t=1,t1,t2;t<=m;++t){
t1=qr(),t2=qr();
int g=pre::lca(t1,t2);
int dis=d[t1]+d[t2]-d[g]-d[g];
if(d[t1]-d[g]==w[g]) ++ans[g];
q1[t1].push_back((E){d[t1],1}); q1[g].push_back((E){d[t1],-1});
q2[t2].push_back((E){d[t2]-dis,1}); q2[g].push_back((E){d[t2]-dis,-1});
}
solve(1,0);
for(int t=1;t<=n;++t) printf("%d ",ans[t]);
putchar('\n');
return 0;
}

换教室(期望DP)

换教室

注意这是期望,所以要计算失败的贡献。

//@winlere
#include<bits/stdc++.h>
#define int long long
using namespace std; typedef long long ll;
template < class ccf > inline ccf qr(ccf ret){ ret=0;
register char c=getchar();
while(not isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+c-48,c=getchar();
return ret;
}inline int qr(){return qr(1);}
const int maxn=25;
const ll mod=1e9+7;
inline ll Pow(ll base,ll p){
base%=mod;
register ll ret=1;
for(;p;p>>=1,base=base*base%mod)
if(p&1) ret=ret*base%mod;
return ret;
}
ll data[maxn],s,ans,inv[maxn]={1},jie[maxn]={1};
int n; inline ll C(const ll&n,const ll&m){
if(n<m||m<0||n<0)return 0;
if(n==m)return 1;
register ll ret=inv[m];
for(register ll t=n;t>=n-m+1ll;--t)
ret=t%mod*ret%mod;
return ret;
}
#undef int
int main(){
#define int long long
#ifndef ONLINE_JUDGE
freopen("in.in","r",stdin);
//freopen("out.out","w",stdout);
#endif
for(register int t=1;t<maxn;++t)
inv[t]=inv[t-1]*Pow(t,mod-2ll)%mod;
n=qr();s=qr(1ll);ans=C(s+n-1ll,n-1ll);
for(register int t=1;t<=n;++t)
data[t]=qr(1ll);
for(register int t=1,edd=1<<n,cnt=0;t<edd;++t){
ll f=cnt=0,delt;
for(register int i=1;i<=n;++i)
if(t<<1>>i&1)
f+=data[i]+1ll,++cnt;
delt=C(s-f+n-1ll,n-1ll);
if(cnt&1) ans=(ans-delt)%mod,ans=ans<0?ans+mod:ans;
else ans=(ans+delt)%mod;
}
cout<<ans<<endl;
return 0;
}

组合数问题(二维前缀和)

\(O(n^2)\)处理组合数然后前缀和即可。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define RP(t,a,b) for(int t=(a),edd=(b);t<=edd;t++)
typedef long long ll;
inline ll qr(void){
char c=getchar();
int x=0,q=1;
while(c<48||c>57)
q=c==45?-1:q,c=getchar();
while(c>=48&&c<=57)
x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*q;
}
const int maxn=2002;
ll T,k;
int l,r;
int c[maxn][maxn]={1},ans[maxn][maxn];
int main(){
T=qr();k=qr();
c[1][0]++;
c[1][1]++;
RP(t,2,2000){
c[t][0]=1;
RP(i,1,t){
c[t][i]=(c[t-1][i-1]+c[t-1][i])%k;
ans[t][i]=ans[t-1][i]+ans[t][i-1]-ans[t-1][i-1];
if(!c[t][i]) ans[t][i]++;
}
ans[t][t+1]=ans[t][t];
}
while(T--){
l=qr();
r=qr();
if(r>l) r=l;
cout<<ans[l][r]<<endl;
}
return 0;
}

蚯蚓(队列)

堆只能获得75分(不知道fib和配对堆能不能更高)。受到一堆题的启发,考虑一下用队列维护这个堆。

处理每秒的增量直接记录一个变量即可,注意到当元素push进去时要先减去当前总增量,下次取出时才能计算出真正的增量。

可以发现,后面生成的蚯蚓一定比先前生成的蚯蚓要短。

但是生成的两蚯蚓之间没有大小的保证。

所以维护三个队列分别表示:原蚯蚓,\(u \times p\)的蚯蚓,\(u-u\times p\)的蚯蚓。每次从三个队列队首取大的那个。

复杂度\(O(n)\) 居然可以过CCF老年机?

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#include<vector>
#define int long long using namespace std; typedef long long ll;
inline int qr(){
register int ret=0,f=0;
register char c=getchar();
while(c<48||c>57)f|=c==45,c=getchar();
while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
} const int maxn=1e5+1;
queue<int> q[4];
int data[maxn];
int n,m,Q,u,v,T;
double f; inline int getBig(){
int g=-1e18,ret=-1;
for(int t=1;t<=3;++t)
if(q[t].size()&&q[t].front()>g)
g=q[t].front(),ret=t;
return ret;
} signed main(){
n=qr(); m=qr(); Q=qr(); u=qr(); v=qr(); T=qr();
f=(double)u/v;
for(int t=1;t<=n;++t) data[t]=qr();
sort(data+1,data+n+1);
for(int t=n;t;--t) q[1].push(data[t]);
for(int t=0,g=T;t<m;++t){
int l=getBig();
int now=q[l].front()+t*Q;
int f1=now*f,f2=now-f1;
q[l].pop(); q[2].push(f1-(t+1)*Q); q[3].push(f2-(t+1)*Q);
if(--g==0) g=T,printf("%lld ",now);
}
putchar('\n');
for(int t=1,g=T;t<=m+n;++t){
int l=getBig();
int now=q[l].front()+m*Q;
if(--g==0) g=T,printf("%lld ",now);
q[l].pop();
}
putchar('\n');
return 0;
}

愤怒的小鸟(搜索)

剪枝然后随机化,注意到枚举一次抛物线后,可能打中很多鸟,那些鸟就不必再和当前鸟枚举抛物线了。

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define x first
#define y second
#define pf(x) ((x)*(x)) using namespace std; typedef long long ll;
inline int qr(){
register int ret=0,f=0;
register char c=getchar();
while(c<48||c>57)f|=c==45,c=getchar();
while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int maxn=21;
int n,W1;
typedef pair<long double,long double> Pt;
const long double eps=1e-10;
Pt data[maxn];
bool hit[maxn];int ans; struct axx{
long double a,b;
axx(){a=b=0;}
axx(const long double&x,const long double&y){a=x,b=y;}
inline bool operator*(const Pt&s){return abs((a*s.first+b)*s.first-s.second)<=eps;}
inline bool operator ==(const axx&s){return abs(a-s.a)<=eps&&abs(b-s.b)<=eps;}
inline void print(){
printf("{%Lfx*x+%Lfx}\n",a,b);
}
}Err(1,1); inline axx gen(const Pt&a,const Pt&b){
long double mu=a.x*pf(b.x)-pf(a.x)*b.x;
if(-eps<=mu&&mu<=eps) return Err;
long double z1=b.y*a.x-a.y*b.x;
long double z2=b.y*pf(a.x)-a.y*pf(b.x);
axx ret(z1/mu,-z2/mu);
if(ret.a>=-eps) return Err;
return ret;
} void dfs(const int&now,const int&s,const int&tol){
if(ans<=s) return;
if(tol==n) return ans=s,void();
if(now>n) return;
if(hit[now]) return dfs(now+1,s,tol);
bool f=0,temp[maxn];
for(int t=1;t<=n;++t) temp[t]=hit[t];
unsigned short sav[maxn];
sav[0]=0;
for(int t=now+1;t<=n;++t)
if(!temp[t]){
axx Cur=gen(data[now],data[t]);
if(Cur==Err) continue;
for(int i=now;i<=n;++i)
if((!hit[i])&&(Cur*data[i]))
sav[++*sav]=i,hit[i]=1,temp[i]=1;
dfs(now+1,s+1,tol+*sav);
for(int i=1;i<=*sav;++i) hit[sav[i]]=0;
sav[0]=0;
f=1;
}
if(!f) hit[now]=1,dfs(now+1,s+1,tol+1),hit[now]=0;
} int main(){
srand(time(NULL));
int T=qr();
while(T--){
n=qr(); W1=qr();
for(int t=1;t<=n;++t) scanf("%Lf%Lf",&data[t].x,&data[t].y);
stable_sort(data+1,data+n+1);
n=unique(data+1,data+n+1)-data-1;
random_shuffle(data+1,data+n+1);
ans=n;
dfs(1,0,0);
printf("%d\n",ans);
}
return 0;
}

【题解】NOIP2016 提高组 简要题解的更多相关文章

  1. 【题解】NOIP2017 提高组 简要题解

    [题解]NOIP2017 提高组 简要题解 小凯的疑惑(数论) 不讲 时间复杂度 大力模拟 奶酪 并查集模板题 宝藏 最优解一定存在一种构造方法是按照深度一步步生成所有的联通性. 枚举一个根,随后设\ ...

  2. 【题解】NOIP2016提高组 复赛

    [题解]NOIP2016提高组 复赛 传送门: 玩具谜题 \(\text{[P1563]}\) 天天爱跑步 \(\text{[P1600]}\) 换教室 \(\text{[P1850]}\) 组合数问 ...

  3. NOIP2016提高组解题报告

    NOIP2016提高组解题报告 更正:NOIP day1 T2天天爱跑步 解题思路见代码. NOIP2016代码整合

  4. [题解]noip2016普及组题解和心得

    [前言] 感觉稍微有些滑稽吧,毕竟每次练的题都是提高组难度的,结果最后的主要任务是普及组抱一个一等奖回来.至于我的分数嘛..还是在你看完题解后写在[后记]里面.废话不多说,开始题解. 第一题可以说的内 ...

  5. [日记&做题记录]-Noip2016提高组复赛 倒数十天

    写这篇博客的时候有点激动 为了让自己不颓 还是写写日记 存存模板 Nov.8 2016 今天早上买了两个蛋挞 吃了一个 然后就做数论(前天晚上还是想放弃数论 但是昨天被数论虐了 woc noip模拟赛 ...

  6. 题解 P1850 [NOIP2016 提高组] 换教室

    做完这道题才略微感觉自己懂了一点关于概率与期望的知识QAQ... 一:关于概率与期望的定义 转载节选于blog 1.什么是数学期望? 数学期望亦称期望.期望值等.在概率论和统计学中,一个离散型随机变量 ...

  7. NOIP2017提高组day2T1题解(奶酪)

    题目链接:奶酪 这道题还是很水的,在下拿了满分. 并没有用什么高级的算法,我讲一下基本思路. 我们把每个洞都视为一个节点. 我们读入相关数据后,就先进行预处理,通过每个节点的信息和题目的规定,建立一张 ...

  8. nowcoder提高组2题解

    T1 化一下试子就ok code #include<cstdio> #include<algorithm> inline long long read() { long lon ...

  9. 牛客NOIP提高组(三)题解

    心路历程 预计得分:$30 + 0 + 0 = 30$ 实际得分:$0+0+0= 0$ T1算概率的时候没模爆long long了... A 我敢打赌这不是noip难度... 考虑算一个位置的概率,若 ...

随机推荐

  1. iphone 内存检测工具

    http://latest.docs.nimbuskit.info/NimbusOverview.html Nimbus Overview Sub-Modules Sensors Overview L ...

  2. This cache store does not support tagging.

    用户权限管理系统 https://github.com/Zizaco/entrust 再添加角色的时候... 报了一个错.. BadMethodCallException in Repository. ...

  3. Laravel / PHP 扩展包视频教程

    https://laravel-china.org/courses/laravel-package 每周精选两个以上扩展包进行讲解,涵盖 PHP 和 Laravel 相关的最新.最热.最常用的扩展包. ...

  4. 从 Apache ORC 到 Apache Calcite | 2019大数据技术公开课第一季《技术人生专访》

    摘要: 什么是Apache ORC开源项目?主流的开源列存格式ORC和Parquet有何区别?MaxCompute为什么选择ORC? 如何一步步成为committer和加入PMC的?在阿里和Uber总 ...

  5. idea actiBPM插件生成png文件 (解决没有Diagrams或Designer选项问题)

    版权声明:随便转, 记得给个链接过来哦 https://blog.csdn.net/wk52525/article/details/79362904 idea对activiti工作流的支持没有ecli ...

  6. Git篇

    安装之后第一步 安装 Git 之后,你要做的第一件事情就是去配置你的名字和邮箱,因为每一次提交都需要这些信息: git config --global user.name "bukas&qu ...

  7. Codeforces Round #200 (Div. 1 + Div. 2)

    A. Magnets 模拟. B. Simple Molecules 设12.13.23边的条数,列出三个等式,解即可. C. Rational Resistance 题目每次扩展的电阻之一是1Ω的, ...

  8. fatal: Not a git repository (or any of the parent directories)

    当从github.com上面下载下了Firmware后,无意中删除了Firmware目录下的.git文件夹,再去编译就会出现:   fatal: Not a git repository (or an ...

  9. java 内省 了解JavaBean

    JavaBean是一种特殊的Java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则. 如果要在两个模块之间传递多个信息,可以将这些信息封装到一个Jav ...

  10. 解决 el-autocomplete 不显示及没数据时闪一下的问题

    项目中用到了elementUI中的远程搜索即 el-autocomplete 组件,估计首次使用的都会遇到一些小问题,只要你能认真看完并且耐心理解,保证能帮到你,效果图如下: 组件代码: <el ...