day1

T1 玩具谜题

https://www.luogu.org/problemnew/show/P1563

本题主要考察两个问题

1、你是否会编程

2、你是否会取模

随便水水就过去了

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int MAXN=1e5+5,INF=1e9+5;
typedef long long ll;
int n,m;
struct toy
{int d;char s[15];
}toy[MAXN];
int main()
{//freopen("toy.in","r",stdin);//freopen("toy.out","w",stdout);std::scanf("%d%d",&n,&m);    for(int i=0;i<n;i++){std::scanf("%d",&toy[i].d);scanf("%s",toy[i].s);}int now=0;while(m--){int a,s;std::scanf("%d%d",&a,&s);if(toy[now].d==0){if(a==0){now=(now-s+n)%n;} else{now=(now+s)%n;}}elseif(a==0) {now=(now+s)%n;}else {now=(now-s+n)%n;}}printf("%s\n",toy[now].s);return 0;
}

T2 天天爱跑步

https://www.luogu.org/problemnew/show/P1600

这道题的难度应该是今年来的所有noip中最难之一的吧(个人感觉从11年开始最难的三道题就是12年day2的疫情控制、这道题还有17年day2的宝藏)

思路是倍增/tarjan/链剖求lca,然后利用lca、树深度的特殊性质查询每个查询上子树的点满足的条件,然后用一个桶来装并统计,然后就再减去其lca的贡献值(虽然说很多标程上都说这个是差分,但是实际上我觉得和差分还是有一点区别,虽然说确实要用到差分的思想),当然这么说好像有些抽象,所以我们来稍微详细地讲一下这道题

每一条路径我们都可以把其看成两段,一段是起始点u到lca的路径,另一段则是lca到v的路径

然后我们可以看到,在u到lca的路径上的任意一个节点x,当deep[u]-deep[x]=w[x]时,u会对x点有贡献,移项过后我们就可以得到deep[u]=deep[x]+w[x],所以我们可以直接开一个桶bac[],用dfs暴力统计一遍满足条件的点,减去lca的贡献就搞定了

// luogu-judger-enable-o2
#include<cstdio>
#include<vector>
#include<iostream>
#define  RG register
const int MAXN=6e5+5;
const int P=17+1;
char buffer[MAXN],*S=buffer,*T=buffer;
inline int read()
{char ch=getchar();int sum=0;while(!(ch>='0'&&ch<='9'))ch=getchar();while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=getchar();return sum;
}
void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>9)print(x/10);putchar(x%10+'0');
}
int n,m;
struct Edge
{int nxt;int to;
}edge[MAXN<<1];
int num;
int head[MAXN];
void add(int from,int to)
{edge[++num].nxt=head[from];edge[num].to=to;head[from]=num;
}
int dist[MAXN];
struct Chain
{int from;int LCA;int len;int to;
}mp[MAXN];
int anc[MAXN][P+1];
int dep[MAXN];
int w[MAXN];
int ans[MAXN];
std::vector<int>G[MAXN];
std::vector<int>V[MAXN];
int D[MAXN<<1];
int cnt[MAXN];
int Mark[MAXN];
void dfs1(int u,int f)
{anc[u][0]=f;for(RG int p=1;p<=P;p++){anc[u][p]=anc[anc[u][p-1]][p-1];}for(RG int i=head[u];i;i=edge[i].nxt){int v=edge[i].to;if(v==f){continue;}dep[v]=dep[u]+1;dist[v]=dist[u]+1;dfs1(v,u);}
}
inline int lca(int u,int v)
{if(dep[u]<dep[v]){std::swap(u,v);}int t=dep[u]-dep[v];for(RG int p=0;t;t>>=1,p++){if(t&1){u=anc[u][p];}}if(u==v) return u;for(RG int p=P;p>=0;p--){if(anc[u][p]!=anc[v][p]){u=anc[u][p];v=anc[v][p];}}return anc[u][0];
}
void Dfs(int x,int f)
{int cc=D[dep[x]+w[x]],co=D[w[x]-dep[x]+MAXN];for(RG int i=head[x];i;i=edge[i].nxt){int v=edge[i].to;if(v==f) continue;Dfs(v,x);}D[dep[x]]+=Mark[x];for(RG int i=0;i<V[x].size();i++){int v=V[x][i];D[mp[v].len-dep[mp[v].to]+MAXN]++;}cnt[x]+=D[dep[x]+w[x]]-cc+D[w[x]-dep[x]+MAXN]-co;for(RG int i=0;i<G[x].size();i++){int v=G[x][i];D[dep[mp[v].from]]--,D[mp[v].len-dep[mp[v].to]+MAXN]--;}return;
}
void solve()
{for(RG int i=1;i<=m;i++){mp[i].LCA=lca(mp[i].from,mp[i].to);mp[i].len=dist[mp[i].from]+dist[mp[i].to]-2*dist[mp[i].LCA];G[mp[i].LCA].push_back(i);V[mp[i].to].push_back(i);Mark[mp[i].from]++;if(dep[mp[i].from]==dep[mp[i].LCA]+w[mp[i].LCA]) {cnt[mp[i].LCA]--;}} Dfs(1,0);
}
int main()
{n=read();m=read();for(RG int i=1;i<=n-1;i++){int u,v;u=read();v=read();add(u,v);add(v,u);}for(RG int i=1;i<=n;i++){w[i]=read();}for(RG int i=1;i<=m;i++){mp[i].from=read();mp[i].to=read();}dfs1(1,0);solve();for(RG int i=1;i<=n;i++) {print(cnt[i]);printf(" ");}return 0;
}

day1 T3 换教室

https://www.luogu.org/problemnew/show/P1850

从实现难度上来讲甚至都不能称得上是noip提高组的题。。。只要你知道期望dp的基本套路就能直接做出来,方程思路都清晰明了而且实现相当简单,几个for循环丢进去就能轻松ac

我们先定义一下状态,状态时dp[i][j][0/1]的一个三维数组,第一维i表示前i间教室,j表示目前为止已经申请了j次更换(算上这件教室),第三维的0/1则分别表示这次这件教室申不申请更换

那么我们可以轻松地得到状态转移方程(虽然很轻松,但是方程又丑又长,而且还容易写错)

当然这道题里还要注意两个点,第一,这张图没有跟你说直接连的边是最短的,所以得先用Floyed跑一遍任意两点间的最短路g[i][j]。

第二,这道题可以在同一间教室连边(蠢炸了。。。。。),所以在建边的时候你要判等。关键是如果你忽略了这一点,这道题你大概会丢掉14个左右的点(出题人估计也是知道这道题太简单了,所以故意挖一些坑给人跳)

dp[i][j][0]=std::min(dp[i-1][j][0]+g[c[i-1]][c[i]],dp[i-1][j][1]+g[c[i-1]][d[i]]*k[i]+g[c[i-1]][c[i]]*(1-k[i]));(这个方程其实挺短的,接下来才是最蛋疼的)

dp[i][j][1]=std::min(dp[i][j][1],dp[i-1][j-1][0]+g[c[i-1]][d[i]]*k[i]+(1-k[i])*g[c[i-1]][c[i]]+dp[i-1][j-1][1]+g[d[i-1]][d[i]]*k[i-1]*k[i]+g[c[i-1]][d[i]]*(1-k[i-1])*k[i]+g[d[i-1]][c[i]]*k[i-1]*(1-k[i])+g[c[i-1]][c[i]]*(1-k[i-1])*(1-k[i]))(方程的意思真心很简单,但是就是能够写到人心态爆炸)

#include<cstdio>
#include<cstring>
#include<algorithm>
const int MAXN=2005;
const int MAXM=305;
const double INF=1e9+7;
int ln,lm,n,m;
int c[MAXN];
int d[MAXN];
double k[MAXN];
int G[MAXM][MAXM];
double dp[MAXN][MAXN][2];
void floyed()
{for(int k=1;k<=n;k++){for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){G[i][j]=std::min(G[i][j],G[i][k]+G[k][j]);}}}
}
void solve()
{for(int i=1;i<=ln;i++)for(int j=0;j<=lm;j++) {dp[i][j][0]=dp[i][j][1]=INF;}dp[0][0][0]=0;for(int i=1;i<=ln;i++){for(int j=0;j<=lm;j++){dp[i][j][0]=std::min(dp[i-1][j][0]+G[c[i-1]][c[i]],dp[i-1][j][1]+1.0*G[d[i-1]][c[i]]*k[i-1]+G[c[i-1]][c[i]]*(1-k[i-1]));if(j>0){dp[i][j][1]=dp[i-1][j-1][0]+1.0*G[c[i-1]][d[i]]*k[i]+1.0*G[c[i-1]][c[i]]*(1-k[i]);}if(j>1){dp[i][j][1]=std::min(dp[i][j][1],dp[i-1][j-1][1]+k[i-1]*(G[d[i-1]][d[i]]*k[i]+G[d[i-1]][c[i]]*(1-k[i]))+(1-k[i-1])*(G[c[i-1]][d[i]]*k[i]+G[c[i-1]][c[i]]*(1-k[i])));}}}
}
int main()
{//freopen("classroom.in","r",stdin);//freopen("classroom.out","w",stdout);std::scanf("%d%d%d%d",&ln,&lm,&n,&m);for(int i=1;i<=ln;i++){std::scanf("%d",c+i);}for(int i=1;i<=ln;i++){std::scanf("%d",d+i);}for(int i=1;i<=ln;i++){std::scanf("%lf",k+i);}for(int i=1;i<=n;i++) {for(int j=i+1;j<=n;j++){G[i][j]=G[j][i]=INF;}}for(int i=1;i<=m;i++){int u,v,w;std::scanf("%d%d%d",&u,&v,&w);if(u!=v){G[u][v]=G[v][u]=std::min(G[u][v],w);}}floyed();solve();double ans=INF;for(int j=0;j<=lm;j++) {ans=std::min(ans,std::min(dp[ln][j][0],dp[ln][j][1])); }std::printf("%.2f",ans);return 0;
}

day2 T1 组合数问题

https://www.luogu.org/problemnew/show/P2822

O(n^2)预处理,O(1)查询,注意n、m的大小关系,只要懂点儿数论都会做

#include<cstdio>
#include<cstring>
const int MAXN=2005;
int t,k;
int c[MAXN][MAXN];
int s[MAXN][MAXN];
void prepare()
{for(int i=0;i<=2000;i++){c[i][0]=1;}c[1][1]=1;for(int i=2;i<=2000;i++){for(int j=1;j<=2000;j++){c[i][j]=(c[i-1][j-1]+c[i-1][j])%k;}}for(int i=1;i<=2000;i++){for(int j=1;j<=i;j++){s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1];if(c[i][j]==0) {s[i][j]+=1;}}s[i][i+1]=s[i][i];}
}
int main()
{//std::freopen("problem.in","r",stdin);//std::freopen("problem.out","w",stdout);std::scanf("%d%d",&t,&k);prepare();while(t--){int n,m;std::scanf("%d%d",&n,&m);if(m>n) m=n;std::printf("%d\n",s[n][m]);}return 0;
}

T2  蚯蚓

https://www.luogu.org/problemnew/show/P2827

因为比例跟初始数据的大小是一定的,所以我们可以发现每一次分出来的数据中,原数据中大的,剪下来放到另外一个数组后依然是更大的,所以我们用三个递减的单调队列来模拟一边过程就能够输出正确的结果

// luogu-judger-enable-o2
#include<cstdio>
#include<cmath>
#include<algorithm>
const int MAXN=7e6+5;
int n,m,q,u,v,t;
int a[MAXN];
int q1[MAXN];
int q2[MAXN];
int q3[MAXN];
int h1=1;
int t1=0;
int h2=1;
int t2=0;
int h3=1;
int t3=0;
bool cmp(const int &a,const int &b)
{return a>b;
}
int main()
{std::scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t);double p=u*1.0/v;for(int i=1;i<=n;i++){std::scanf("%d",a+i);q1[i]=a[i];q1[i]+=m*q;}std::sort(q1+1,q1+1+n,cmp);int num1=m/t;int num2=(n+m)/t;t1=n;for(int i=1;i<=m;i++){int a=0;int b=0;int c=0;if(h1<=t1){a=q1[h1];}if(h2<=t2){b=q2[h2];}if(h3<=t3){c=q3[h3];}int d=std::max(a,std::max(b,c));if(a==d&&h1<=t1){h1++;}else if(b==d&&h2<=t2){h2++;}else h3++;d-=(m-i+1)*q;if(i%t==0&&num1){std::printf("%d ",d);num1--;}int z1=floor(d*p);int z2=d-z1;if(z1>z2){q2[++t2]=z1+(m-i)*q;q3[++t3]=z2+(m-i)*q;}else {q2[++t2]=z2+(m-i)*q;q3[++t3]=z1+(m-i)*q;}}std::printf("\n");int i=0;while(num2) { ++i;int a=0;int b=0;int c=0;if(h1<=t1) a=q1[h1];if(h2<=t2) b=q2[h2];if(h3<=t3) c=q3[h3];int d=std::max(a,std::max(b,c));if(i%t==0&&num2) {printf("%d ",d);num2--;}if(a==d&&h1<=t1)++h1;else if(b==d&&h2<=t2)++h2;else ++h3;}return 0;
}

T3 愤怒的小鸟

状压dp或者dfs都能过,但是值得注意的一点是状压的时候,要更新的状态不要一个一个去枚举,查找到第一个没有被更新的猪在用它来更新,这样可以防止被卡常。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
const int MAXN=1<<19-1;
int dp[1<<19-1];
int g[19][19];
double x[MAXN];
double y[MAXN];
int main()
{int T;std::scanf("%d",&T);while(T--){std::memset(g,0,sizeof(g));std::memset(dp,127,sizeof(dp));dp[0]=0;int n,m;std::scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){std::scanf("%lf%lf",&x[i],&y[i]);}for(int i=1;i<=n;i++){for(int j=i+1;j<=n;j++){/*double x1=x[i];double y1=y[i];double x2=x[j];double y2=y[j];double a=(y2*x1-y1*x2)/(x1*x2*(x2-x1));double b=(y2*x1*x1-y1*x2*x2)/(x1*x2*(x1-x2));*/double x1=x[i]*x[i]*x[j];double x2=x[i]*x[j]*x[j];double y1=y[i]*x[j];double y2=y[j]*x[i];double a=(y2-y1)/(x2-x1);double b=(y[i]-a*x[i]*x[i])/x[i];if(b>0&&a<0){for(int k=1;k<=n;k++){if(fabs(x[k]*x[k]*a+x[k]*b-y[k])<1e-7){g[i][j]=g[i][j]|(1<<(k-1));}} }}}for(int s=0;s<=(1<<n)-1;s++){int t=1;while((s>>(t-1))&1){t++;}dp[s|1<<(t-1)]=std::min(dp[s|1<<(t-1)],dp[s]+1);for(int j=t+1;j<=n;j++){dp[s|g[t][j]]=std::min(dp[s|g[t][j]],dp[s]+1);}}std::printf("%d\n",dp[(1<<n)-1]);}
}

总的来说day1难于day2吧。。。day2的题真正基础扎实的人拿到240分以上都不难

noip2016题解相关推荐

  1. NOIp2016 题解

    如题 Day1 1.玩具迷题 2.天天爱跑步 3.换教室 Day2 1.组合数问题 2.蚯蚓 3.愤怒的小鸟

  2. NOIP2016普及组复赛第一题的AC程序加题解pascal

    P老师需要去商店买n支铅笔作为小朋友们参加NOIP的礼物.她发现商店一共有 3种包装的铅笔,不同包装内的铅笔数量有可能不同,价格也有可能不同.为了公平起 见,P老师决定只买同一种包装的铅笔.商店不允许 ...

  3. NOIP2016天天爱跑步 题解报告【lca+树上统计(桶)】

    题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nn个 ...

  4. #185. [NOIP2016 提高组] 蚯蚓题解

    #185. [NOIP2016 提高组] 蚯蚓题解 题目描述 本题中,我们将用符号 ⌊c⌋\lfloor c \rfloor⌊c⌋ 表示对 ccc 向下取整,例如:⌊3.0⌋=⌊3.1⌋=⌊3.9⌋= ...

  5. NOIP2016 普及组 总结+题目吐槽+代码+简单题解

    提高组回来之后,像往年一样,做了一下普及组的题 先吐槽一下 T1 这题一眼看上去以为可以用不同种类的铅笔,没想到只能用一种种类,我240B搞定 #include<cstdio> int m ...

  6. 题解 【NOIP2016】组合数问题

    [NOIP2016]组合数问题 Description Input 第一行有两个整数t, k,其中t代表该测试点总共有多少组测试数据,k的意义见[问题描述]. 接下来t行每行两个整数n, m,其中n, ...

  7. NOIP2016提高组 第一天第二题 天天爱跑步running 题解

    题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 个结点 ...

  8. 【题解】NOIP-2016 天天爱跑步

    题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nnn ...

  9. NOIP2016 普及组第四题 魔法阵magic 题解

    题目描述 六十年一次的魔法战争就要开始了,大魔法师准备从附近的魔法场中汲取魔法能量. 大魔法师有m个魔法物品,编号分别为1,2,-,m.每个物品具有一个魔法值,我们用Xi表示编号为i的物品的魔法值.每 ...

  10. NOIP2016提高组 第二天第三题 愤怒的小鸟angrybirds 题解

    题目描述 Kiana最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于(0,0)处,每次Kiana可以用它向第一象限发射一只红色的小鸟,小鸟们的飞行轨迹均为形 ...

最新文章

  1. 量子神经网络:人工智能研究的新范式
  2. 配置 docker0 网桥
  3. 2015-12-03 AD中用户属性Lastlogon与LastlogonTimeStamp的区别
  4. wpsppt如何虚化图片_PPT模仿之路——图片以及笔画的虚化
  5. 直接请求接口_http类型的post和get接口测试
  6. python如何关闭multiprocess_python 开启进程两种方法 multiprocessing模块 介绍
  7. 【限时免费】从入门到实战,5节课玩转Kafka!赢音箱、书籍好礼!
  8. 一段超级好的..漂浮广告代码..精一下..
  9. 找出数组的最大公约数
  10. bootstrap学习记录
  11. Silverlight 与 WPF 的一些差异
  12. websocket替代方案_码农手记 | 前后端实时交互方案概述
  13. eureka集群 ha_SpringCloud如何实现Eureka集群、HA机制-百度经验
  14. 2019春季PAT题解
  15. 节假日查询API接口上线
  16. nape.dynamics.InteractionFilter
  17. [转载]一个程序员心态决定成败
  18. B站付费视频使up主掉粉过万
  19. 智慧教室—基于人脸表情识别的考试防作弊系统
  20. Android学习资源汇总

热门文章

  1. 正确的加密存储密码防止被拖库(脱裤)保护用户登录安全
  2. java resourcebundle properties_Java使用Properties类和ResourceBundle类读取properties文件
  3. VectorDraw Web JS 9.9 Crack
  4. 风行状告芒果卫视,电视台“耍霸道”屡禁不止?
  5. 开宗明义—UEFI介绍 (二)
  6. 10月书讯(上) | 小长假我读这些新书
  7. vtiger 安装中文语言包(汉化的步骤)--拓展繁体中文
  8. 汉王手写输入法android,汉王手写输入法
  9. Java读取文件方法大全
  10. VARCHART XGantt资讯:视觉计划咨询服务现已在AppSource上