关于\(NOIP2017\)的题目讲解

1.小凯的疑惑

题目描述:

小凯手中有两种面值的金币,两种面值均为正整数且彼此互素。每种金币小凯都有 无数个。在不找零的情况下,仅凭这两种金币,有些物品他是无法准确支付的。现在小 凯想知道在无法准确支付的物品中,最贵的价值是多少金币?注意:输入数据保证存在 小凯无法准确支付的商品。

讲解:

其实这道题目可以使用很简单的方法做出来。大家也知道就是\(A * B - A - B\)。那么这个解到底是怎么推出来的呢?
首先\(A = B\)的情况不用说。那不妨设\(A < B\)。
假设\(A\)取了\(X\)张,\(B\)取了\(Y\)张,那么总钱数就是\(A \times Y + B \times Y = K\)。
我们要找出第一个使得\(A \times Y + B \times Y = K\)无解的情况。
根据欧几里德算法我们知道只有满足\(gcd(A, B) ~ | ~ (A \times X + B \times Y)\),才有可能使上式有解。因为题目保证\(A, B\)互素,那么\(gcd(A, B) = 1\),自然满足条件。

假设找到一组\((X_0, Y_0)\)满足\(A \times X_0 + B \times Y_0 = 1\),得到\(A \times X_0 \times K+ B \times Y_0 \times K = K\),它的其中一个解为\((X_0 \times K, Y_0 \times K)\),所以我们得到所有的解是\((KX_0 + \frac{Bt}{gcd(A, B)},KY_0 + \frac{At}{gcd(A, B)}) = (KX_0 + Bt,KY_0 + At)\)。

在这里我们发现\(X+0\)或者\(Y_0\)一定有一项是\(\leq 0\)的,不然绝对构不成式子\(A \times X_0 + B \times Y_0 = 1\)。假设\(K = A \times B\),那么满足式子的\(X, Y\)一定有一项是小于等于\(0\)的,这与题意相悖,那么我们得到\(A \times Y + B \times Y = A \times B\)无解。

然后我们按照上面的思路依然可以推得\(A \times Y + B \times Y = A \times B + C\)\((C > 0)\)是一定有解的。所以\(K\)便是最大的凑不出来的钱数。这是必须要拿的情况,然而我们还可以不拿,所以总钱数就是\(X \times T - X - Y\)。

当然这种方法可行,但是我们发现这个题所给的数据范围\(1 \leq A, B \leq 10^9\)并不是只有\(O(1)\)才能过,\(O(log)\)级别的算法也不会超时。所以我们试图扩展欧几里德

如果我们事先假设\(K\)为最大的不合法的数,那么\(K + 1 = K'\)就一定合法,那么就有\(A \times X + B \times Y = K'\)一定成立,并且\(A \times X_1 + B \times Y_1 = K\)一定不成立。那么我们就要想办法使得最大的\(X_{1max} < 0\),并且最大的\(Y_{1max} < 0\)。

那么得到最后的\(K\)就是\(A (X_{1max} - 1 ) + B(Y_{1max} - 1)\)。这个式子很显然是可以用扩欧求出的。

2.逛公园

题目描述 :

策策同学特别喜欢逛公园。公园可以看成一张NN个点MM条边构成的有向图,且没有 自环和重边。其中1号点是公园的入口,NN号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间。

策策每天都会去逛公园,他总是从1号点进去,从NN号点出来。

策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果1号点 到NN号点的最短路长为dd,那么策策只会喜欢长度不超过d + Kd+K的路线。

策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?

为避免输出过大,答案对PP取模。

如果有无穷多条合法的路线,请输出-1−1。

讲解 :

首先前\(30\)分\(K = 0\)的情况自然很好做,我们直接求一个最短路计数就好了。具体过程不再细讲。(代码现场打的...)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;typedef long long LL ;
const int MAXN = 1200 ;
const int Inf = 0x7fffffff ;inline Read() {int X = 0, F = 1 ; char ch = getchar() ;while (ch > '9' || ch < '0') F = (ch == '-' ? - 1 : 1), ch = getchar() ;while (ch >= '0' && ch <= '9') X = (X << 1) + (X << 3) + (ch ^ 48), ch = getchar() ;return X * F;
}int N, M, Tot, Head[MAXN], D[MAXN], Ans[MAXN] ;
queue<int> Q ; bool Inque[MAXN] ;void ADD(int F, int T, int L) {E[++ Tot].F = F, E[++ Tot].T = T, E[++ Tot].L = L ;E[Tot].Next = H[F], H[F] = Tot ;
}
inline int SPFA() {for (int i = 1 ; i <= N ; i ++) D[i] = Inf ;memset(Inque, 0, sizeof(Inque)) ;memset(Ans, 1, sizeof(Ans)) ;D[1] = 0, Inque[1] = 1, Q.push(1) ;while (! Q.empty()) {int Now = Q.front() ; Q.pop(), Inque[Now] = 0 ;for (int i = H[Now] ; i ; i = E[i].Next) if(D[E[i].T] > D[Now] + E[i].L) {D[E[i].T] = D[Now] + E[i].L ;Ans[E[i].T] = Ans[Now] ;if(! Inque[E[i].T]) Inque[E[i].T], Q.push(E[i].T) ;}   else if(D[E[i].T] == D[Now] + E[i].L)Ans[E[i].T] += Ans[Now] ;}
}int main() {N = Read(), M = Read() ;for (int i = 1 ; i <= M ; i ++) {int X = Read(), Y = Read(), Z = Read() ;ADD(X, Y, L) ;}   SPFA(1) ;if(D[N] == Inf) {puts("No answer") ; return 0 ;}  printf("%d %d", D[N], Ans[N]) ;return 0 ;
}

那么接下来考虑满分做法。

很显然我们要先求出最短路,然后题目说了不超过\(D[N] + K\)的路径都可以被接受,也就是说题目可以允许走”冤枉路“。而这个允许的冤枉路的总长度也就是\(K\)。

每一次我们从\(A\)走到\(B\)点的时候所消耗的冤枉路的容量就是\(Len[A][B] - D[A][B]\)。那么我们就可以以这个\(K\)的容量的余额为限制进行搜索。

在此之前我们需要特判两个情况:永远走不到的点和无限的方案数。

第一个是什么意思呢?其实就是说从这个点开始永远走不到\(N\)号节点,那么我们就可以将它标记,在搜索的时侯直接跳过。就比如下图的\(2\)号节点就一定永远不会走到,那么我们就将它排除。

具体来说,我们将整个图反过来建,然后从\(5\)到\(1\)搜索,途中经过的所有的点肯定都是有机会到达的,而至于\(3\)肯定是搜索不到的。

void Spfa2(){while(! Q.empty()) Q.pop() ;Flag[N] = 1 ; Q.push(N) ;while(! Q.empty()){int Now = Q.front() ; Q.pop()   ;for( int i = H2[Now]; i; i = E2[i].Next)if(! Flag[E2[i].T])Flag[E2[i].T] = 1, Q.push(E2[i].T) ;}
}

至于无限的方案数,情况在这个题里面只有一种:零环。于是当我们搜索到图中存在零环,那么我们就直接输出\(- 1\)。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define MEM(Now, K) memset(Now, K, sizeof(Now))
#define MAXN 100010
#define MAXM 200010
#define RE register
#define Inf 0x7ffffff
#define LL long long
using namespace std ;
int Read(){int X = 0 ; char ch = getchar() ;while(ch > '9' || ch < '0') ch = getchar() ;while(ch >= '0' && ch <= '9')X = (X << 1) + (X << 3) + (ch ^ 48), ch = getchar() ;return X ;
}
int N, M, K, P, H[MAXN], Tot ;
int V[MAXN][55], U[MAXN][55] ;
struct NODE{int F, T, L, Next ;
}E[MAXM << 1], E2[MAXM << 1] ;
inline void Add(int F, int T, int L){E[++ Tot].F = F, E[Tot].T = T, E[Tot].L = L ;E[Tot].Next = H[F], H[F] = Tot ; return  ;
}
int H2[MAXN], Tot2 ;
inline void Add2(int F, int T, int L){E2[++ Tot2].F = F, E2[Tot2].T = T, E2[Tot2].L = L ;E2[Tot2].Next = H2[F], H2[F] = Tot2 ; return   ;
}
int D[MAXN], I[MAXN] ;
queue<int> Q ;
bool Flag[MAXN] ;
void Spfa(){for( int i = 1; i <= N; i ++)D[i] = Inf ;D[1] = 0, Q.push(1) ;   while(! Q.empty()){int Now = Q.front() ; Q.pop() ;for( int i = H[Now]; i; i = E[i].Next){int V = E[i].T ;if(D[V] > D[Now] + E[i].L){D[V] = D[Now] + E[i].L ;Q.push(V) ;}}}
}
void Spfa2(){while(! Q.empty()) Q.pop() ;Flag[N] = 1 ; Q.push(N) ;while(! Q.empty()){int Now = Q.front() ; Q.pop()   ;for( int i = H2[Now]; i; i = E2[i].Next)if(! Flag[E2[i].T])Flag[E2[i].T] = 1, Q.push(E2[i].T) ;}
}
int Dfs(int X, int Y){if(Y < 0) return 0 ;if(V[X][Y] == 1) return - Inf ;if(U[X][Y] != - 1) return U[X][Y] ;V[X][Y] = 1 ; int Ans = 0 ;if(X == N) Ans ++ ;for( int i = H[X]; i; i = E[i].Next){if(Flag[E[i].T] == 0) continue ;int C = Dfs(E[i].T, Y - E[i].L + D[E[i].T] - D[X]) ;if(C == - Inf) return C ;else Ans = (Ans + C) % P ;}U[X][Y] = Ans % P ;V[X][Y] = 0 ;return Ans ;
}
int main(){int T = Read() ;while(T --){MEM(D, 127), MEM(I, 0), MEM(V, 0), MEM(H, 0) ; Tot = 0 ;MEM(E, 0), MEM(E2, 0), MEM(Flag, 0), MEM(H2, 0) ; Tot2 = 0 ;N = Read(), M = Read(), K = Read(), P = Read() ;for( int i = 0; i <= N; i ++)for(int j = 0; j <= 55; j ++)U[i][j] = - 1 ; for( int i = 1; i <= M; i ++){int X = Read(), Y = Read(), Z = Read() ;Add2(Y, X, Z) ; Add(X, Y, Z) ;}Spfa() ;  Spfa2() ; int Ans = Dfs(1, K) ;if(Ans == - Inf) puts("-1") ;else printf("%d\n", Ans) ;}return 0 ;
}

3.奶酪

题目描述:

现有一块大奶酪,它的高度为\(h\),它的长度和宽度我们可以认为是无限大的,奶酪 中间有许多 半径相同 的球形空洞。我们可以在这块奶酪中建立空间坐标系,在坐标系中, 奶酪的下表面为\(z = 0\),奶酪的上表面为\(z = h\)。

现在,奶酪的下表面有一只小老鼠\(Jerry\),它知道奶酪中所有空洞的球心所在的坐 标。如果两个空洞相切或是相交,则\(Jerry\)可以从其中一个空洞跑到另一个空洞,特别地,如果一个空洞与下表面相切或是相交,\(Jerry\)则可以从奶酪下表面跑进空洞;如果 一个空洞与上表面相切或是相交,\(Jerry\)则可以从空洞跑到奶酪上表面。

位于奶酪下表面的 Jerry 想知道,在 不破坏奶酪 的情况下,能否利用已有的空洞跑 到奶酪的上表面去?

空间内两点\(P_1(x_1,y_1,z_1)\)、\(P2(x_2,y_2,z_2)\)的距离公式如下:

\[Dist(P_1, P_2) = \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2 + (z_1 - z_2)^2}\]

讲解:

这大概是\(NOIP2017\)最简单的一道题了。(傻*时间复杂度)

当然你是可以搜索的。但是在这里使用的方法是并查集。

考虑将所有的相交或者相切的空洞并查集起来,然后最后判断是不是存在一个集合既与上表面相交或相切,又与下表面相交或相切。输出结果。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;typedef long long LL ;
const int MAXN = 1000101 ;
const int Inf = 0x7fffffff ;
long long X[MAXN], Y[MAXN], Z[MAXN], F[MAXN] ;
long long F1[MAXN],Tot1, F2[MAXN],. Tot2 ;inline long long Read() {long long X = 0 ; char ch = getchar() ;while (ch > '9' || ch < '0') ch = getchar() ;while (ch >= '0' && ch <= '9')X = (X << 1) + (X << 3) + (ch ^ 48), ch = getchar() ;return X ;
}inline long long POW(LL X) {return X * X ;
}
inline long long Find(int Now) {if (Now == F[Now]) return F[Now] ;else return F[Now] = Find (F[Now]) ;
}
ll dis(ll x,ll y,ll z,ll x1,ll y1,ll z1)
{ return dou(x-x1)+dou(y-y1)+dou(z-z1);}
inline long long Dist(LL X, LL Y, LL Z, LL X1, LL Y1, LL Z1) {return POW(X - X1) + POW(Y - Y1) + POW(Z - Z1) ;
}
int f1[MAXN],f2[MAXN];
inline void Union(int X, int Y) {long long R1 = Find(X), R2 = Find(Y) ;if(R1 != R2) F[R1] = R2 ;
}
int main() {int t,n,h;ll r;long long T = Read() ;while (T --) {long long N = Read(), H = Read(), R = Read() ;long long Tot1 = Tot2 = 0 ;for (int i = 1 ; i <= N ; i ++) F[i] = i ;for (int i = 1 ; i <= N ; i ++) {long long X[i] = Read(), Y[i] = Read(), Z[i] = Read() ;if (Z[i] + R >= H) F1[++ Tot1] = i ;if (Z[i] - R <= 0) F2[++ Tot2] = i ;for (int j = 1 ; j <= i ; j ++) if (Dist(X[i], Y[i], Z[i], X[j], Y[j], Z[j]) <= 4 * R * R)Union(i, j) ;}   long long S = 0 ;for (int i = 1 ; i <= Tot1 ; i ++) {for (int j = 1 ; j <= Tot2 ; j ++)if (Find(F1[i]) == Find(F2[j])) {S = 1 ; break ;}if (S == 1) break ;}if(S == 1) puts("Yes") ;else puts("No") ;}
}

转载于:https://www.cnblogs.com/Yeasio-Nein/p/NOIP2017.html

关于$NOIP2017$的题目讲解相关推荐

  1. 信息学奥赛初赛题目讲解(2)

    嗨嗨嗨,我又来了啊,今天继续为大家带来信息学奥赛初赛题目讲解. 我们看今天的第一题,微信计算机中使用数据库属于哪方面的计算呢?先为大家解释一下,我们现在用的计算机属于微型计算机,世界上第一台计算机是埃 ...

  2. 信息学奥赛初赛题目讲解3

    欢迎收看今天的初赛题目讲解,我是你们的讲解师信息开发者. 我们先来看今天的第一道题,可以看到,第一题是32位机器和64位机器的区别是什么?首先排除掉A,因为显示器是你自己买的,不同与否是看你买的是否相 ...

  3. 蓝桥杯stema考试题目讲解 0814CC02 蜗牛爬井 2021

    题目: 0814CC02 时间限制: 1000MS 内存限制: 65536KB 题目描述: 编程实现:蜗牛爬井 题目描述: 有一口N米深的井,蜗牛从井底向井口爬,白天向上爬3米,晚上向下滑1米,那么蜗 ...

  4. 考研高数之无穷级数题型二:求和函数(题目讲解)

    和函数就是函数项无穷级数的和 在进行具体的题目讲解之前我想说一说个人做题的思路,经过做了一些题可以感受到,求和函数我们的目标就是把一个累加的级数变成用一个函数去表示他,那么我们的目标就很明确了,根据常 ...

  5. python检索地址_35.leetcode题目讲解(Python): 搜索插入位置

    题目如下: image.png 这道题使用双指针折半查找比较容易解,指的注意的是,如果出现插入元素与输入数组里的元素相同,需要插入到相同元素的位置,比如: [8,5,3],5 应该返回1,而不是2. ...

  6. python旋转排序数组_33.leetcode题目讲解(Python):搜索旋转排序数组

    题目如下: 题目 这道题比较简单,不做过多解释了,注意程序终止条件,参考代码如下: class Solution: def search(self, nums, target): "&quo ...

  7. 考研高数之无穷级数题型一:判断收敛性、求收敛半径以及收敛域和收敛区间(题目讲解)

    发现有问题或者需要其他题型讲解请评论区留言~~~ 博主最近在复习考研,发现数一还是有一点点难,并且发现网上专门讲题目的文章比较少,刚好复习完一轮之后停下来总结一下自己踩过的坑和一些心得,其中难免因为理 ...

  8. python计算长方体的表面积公式_892.leetcode题目讲解(Python):三维形体的表面积(Surface Area of 3D Shapes)...

    题目 题目 解题思路 解这道题的思路为,首先获取一个坐标点长方体的表面积,计算公式如下: surface = grid[i][j] * 4 + 2 然后减去其 "上.下.左.右" ...

  9. 考研高数之无穷级数题型三:将函数展开成幂级数和傅里叶级数(题目讲解)

    在无穷级数这一章中,值得注意的有幂级数和傅里叶级数两种,使用它们的目的分别是将分数展开成幂级数和三角函数 在写题之前我们最好先明确一下为什么要进行展开,这样有助于理解 进行展开是为了去除信息冗余,完成 ...

最新文章

  1. Product Backlog:终极任务清单
  2. 爱立信2015谋变之路:结盟思科聚焦IT业务
  3. android studio使用问题——instant run
  4. FPGA配置模式(Altera版)
  5. Redis进阶-JedisCluster初始化 自动管理连接池中的连接 _ 源码分析
  6. 征战蓝桥 —— 2017年第八届 —— C/C++A组第6题——最大公共子串
  7. nginx 1.14.0 配置部署 thinkphp 5.1
  8. 是否应该立即将网站升级到Drupal 8?
  9. VB调用VC DLL函数
  10. css3的cursor
  11. 转载:ADO.NET Entity Framework 试水系列索引(2008/9/9更新,本系列结束)
  12. python 递归函数_Python教程系列之递归函数与匿名函数调用
  13. 在Android中自定义捕获Application全局异常,可以替换掉系统的强制退出对话框(很有参考价值与实用价值)
  14. Windows网络编程之recv()函数
  15. 如何恢复删除的文件?wps文件恢复,4种方法教你找回来
  16. 机器学习项目的实例分析设计(附源码)
  17. 电容屏物体识别_浅谈多点电容屏物体识别,实物识别技术
  18. robots.txt文件信息泄漏
  19. BZOJ3168. 【HEOI2013】钙铁锌硒维生素
  20. 基于MT5的沪深股票回测四--回测

热门文章

  1. oracle begin exception end,Oracle Exception异常处理
  2. 冷链物流计算机控制技术,芜湖WCS仓库控制系统
  3. 基于python的比价系统
  4. 阿里员工感慨:涂鸦和阿里之间选了阿里,涂鸦上市了,小丑竟是我自己
  5. 龙芯7A2000 CAN调试
  6. Python爬虫 - 爬取肯德基门店信息
  7. android导入support-v4包(导包通用教程)
  8. 枚举进程:ring3-ring0
  9. 支付宝 福卡 出花花卡 敬业福 的 福图片
  10. 必收藏宝典:2023纽约通票价格景点大比拼!