[2016.6.11] NOIP模拟题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[2016.6.11] NOIP模拟题相关的知识,希望对你有一定的参考价值。
T1:贪吃蛇snake
【题目描述】
哲哲迷上了一个非常有意思的游戏,这个游戏的内容就是通过上下左右来操作一条蛇的前进,比方说,你现在正在向上走,而你按了一下右,那么这条蛇就会转向右走,很有趣吧!这个游戏的名字叫做贪吃蛇。但是,这个看起来简单的游戏也挺需要操作的,如果你不小心撞到了墙,或是撞到自己的身体的话,你就输了。
可是,哲哲由于手指灵活度不够,经常撞墙而死,所以,他自己设计了一个没有墙的贪吃蛇地图,地图可以表示成若干个点,而你可以操作蛇头从某一个一个点到它相邻的点上。这样,游戏的难度降低了许多,可是哲哲还是有可能挂掉的,因为他可能一不小心吃到自己。
现在,你得到了一些哲哲设计好的地图,哲哲希望你帮他看看他有没有可能一不小心碰到到自己的身体而导致游戏失败,为了简便,这里我们假设哲哲的蛇已经非常长了,长度可以视为无穷大。哲哲可以选任意点作为起点。
【输入数据】
第一行为一个数:t,表示哲哲设计好了t个地图
对于接下来的每一个地图,开头的为两个数:n,m,表示图中有n个点,编号为1~n,m条有向边
接下来m行,每行两个数x,y,表示哲哲可以将蛇从x点移动到y点
【输出数据】
对于每个地图,输出Yes或No,Yes表示哲哲不可能吃到自己,No表示哲哲有吃到自己危险
【输入样例】
2
3 2
1 2
2 3
3 3
1 2
2 3
3 1
【输出样例】
Yes
No
【数据约定】
对于30%的数据,n<=100
对于100%的数据,n<=20000,m<=100000,t<=20,没有自环,允许重边
简化模型&考点:有向图判环
正解:DFS/拓补排序判环均可
考场思路:拓补排序。代码核心全都写对,唯一葬送100分的就是因为t组数据,从第二组数据开始与连边有关的数组未清零
拓补排序的代码:
1 // <snake.cpp> - Sun Jun 12 08:04:25 2016 2 // This file is created by Lai Ruihang‘s black technology automatically. 3 // Copyright (C) 2016 ChangJun High School, Inc. 4 // I don‘t know what this program is. 5 6 #include <cstdio> 7 #include <cstdlib> 8 #include <iostream> 9 #include <algorithm> 10 #include <cstring> 11 #include <cmath> 12 #include <ctime> 13 #include <queue> 14 #include <string> 15 #include <map> 16 typedef long long ll; 17 const int MAXN1 = 20005; 18 const int MAXN2 = 100005; 19 using namespace std; 20 int t; 21 int n, m; 22 int et, fir[MAXN1], to[MAXN2], ne[MAXN2]; 23 int ind[MAXN1]; 24 25 inline int gi() { 26 char c; 27 int sum = 0, f = 1; 28 c = getchar(); 29 while (c < ‘0‘ || c > ‘9‘) { 30 if (c == ‘-‘) 31 f = -1; 32 c = getchar(); 33 } 34 while (c >= ‘0‘ && c <= ‘9‘) { 35 sum = sum * 10 + c - ‘0‘; 36 c = getchar(); 37 } 38 return sum * f; 39 } 40 41 inline void link(int x, int y) { 42 et++; 43 to[et] = y; 44 ne[et] = fir[x]; 45 fir[x] = et; 46 } 47 48 void solve() { 49 n = gi(); 50 m = gi(); 51 for (int i = 1; i <= n; i++) { 52 ind[i] = 0; 53 fir[i] = 0; 54 } 55 for (int i = 1; i <= m; i++) { 56 to[i] = 0; 57 ne[i] = 0; 58 } 59 et = 0; 60 for (int i = 1; i <= m; i++) { 61 int x = gi(); 62 int y = gi(); 63 link(x, y); 64 ind[y]++; 65 } 66 queue <int> que; 67 for (int i = 1; i <= n; i++) 68 if (ind[i] == 0) 69 que.push(i); 70 int cnt = 0; 71 while (que.empty() == 0) { 72 int u = que.front(); 73 que.pop(); 74 for (int i = fir[u]; i; i = ne[i]) { 75 int t = to[i]; 76 if (ind[t] > 0) { 77 ind[t]--; 78 if (ind[t] == 0) 79 que.push(t); 80 } 81 } 82 ind[u]--; 83 cnt++; 84 } 85 if (cnt != n) 86 printf("No\\n"); 87 else 88 printf("Yes\\n"); 89 } 90 91 int main() { 92 freopen("snake.in", "r", stdin); 93 freopen("snake.out", "w", stdout); 94 t = gi(); 95 while (t-- > 0) 96 solve(); 97 return 0; 98 }
-------------------------------------------------------------------------------------------------------------------------------------------------
T2:营养计划egg
【题目描述】
哲哲最近因为醉心于学习中,饮食不太注意,导致身体消瘦,哲哲的妈妈为此深感担忧。为了给哲哲补充点营养,众所周知,鸡蛋这种东西营养丰富,而且更重要的是哲哲也很喜欢吃,鸡蛋不仅含有蛋白质、脂肪、卵黄素、卵磷脂、维生素和铁、钙、钾等人体所需要的矿物质,还含有自然界中最优良的蛋白质。哲哲的妈妈给哲哲制定了一个详细的营养计划,具体内容就是每天吃几个鸡蛋(当然有时候也可能一天不吃一个)。
为了更简洁地描述这个问题,这里我们先假设哲哲的胃口无限大,哲哲的妈妈一共准备了n个鸡蛋,这个营养计划持续m天,计划安排哲哲每天得吃ai个鸡蛋(0<=ai<=n),你需要求出所以方案总数。需要注意的是,方案中的鸡蛋数与顺序无关,比方说如果当n=8时,1,3,4和3,1,4,和4,1,3等方案会被视为同一个方案。需要注意的是,鸡蛋最终必须被吃完。
【输入数据】
第一行,包含两个数n,m
【输出数据】
仅一行,包含一个数ans,即方案总数,由于方案数可能非常大,而哲哲看到大数字就头晕,所以你只需要输出ans mod 19940714即可
【输入样例】
7 3
【输出样例】
8
【数据约定】
对于20%的数据,n,m<=10
对于60%的数据,n,m<=200
对于100%的数据,n,m<=2000
简化模型&考点:DP,整数划分
正解:DP(可选择打表找规律)
考场思路:之前见过一道类似的题目CodeVS 1493糖果,唯一的区别是1493这道题保证每份至少有1。当时没有独自想出来,所以找XZY大爷问了DP方程,不过没有深究,也理解的不透,只记住了,所以今天直接利用DP方程。而这道题每份可以为零,所以可以分类,分成共1天吃n个鸡蛋,共2天吃n个鸡蛋,……,共m天吃0个鸡蛋。设f[i][j]表示前i天吃了j个鸡蛋的总数,则f[i][j] = f[i - 1][j - 1] + f[i][j - i] (j >= i),所以ans = Σf[i][n] (1 ≤ i ≤ m),边界条件为f[0][0] = 1。
1 // <egg.cpp> - Sun Jun 12 08:04:25 2016 2 // This file is created by Lai Ruihang‘s black technology automatically. 3 // Copyright (C) 2016 ChangJun High School, Inc. 4 // I don‘t know what this program is. 5 6 #include <cstdio> 7 #include <cstdlib> 8 #include <iostream> 9 #include <algorithm> 10 #include <cstring> 11 #include <cmath> 12 #include <ctime> 13 #include <queue> 14 #include <string> 15 #include <map> 16 typedef long long ll; 17 const int MAXN = 2005; 18 const int MOD = 19940714; 19 using namespace std; 20 int n, m; 21 int f[MAXN][2 * MAXN]; 22 int ans; 23 24 inline int gi() { 25 char c; 26 int sum = 0, f = 1; 27 c = getchar(); 28 while (c < ‘0‘ || c > ‘9‘) { 29 if (c == ‘-‘) 30 f = -1; 31 c = getchar(); 32 } 33 while (c >= ‘0‘ && c <= ‘9‘) { 34 sum = sum * 10 + c - ‘0‘; 35 c = getchar(); 36 } 37 return sum * f; 38 } 39 40 int main() { 41 freopen("egg.in", "r", stdin); 42 freopen("egg.out", "w", stdout); 43 n = gi(); 44 m = gi(); 45 f[0][0] = 1; 46 for (int i = 1; i <= m; i++) 47 for (int j = i; j <= n; j++) { 48 f[i][j] = f[i - 1][j - 1] + f[i][j - i]; 49 f[i][j] %= MOD; 50 } 51 for (int i = 1; i <= m; i++) { 52 ans += f[i][n]; 53 ans %= MOD; 54 } 55 printf("%d", ans); 56 return 0; 57 }
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
T3:购物狂人shopping
【题目描述】
哲哲喜欢购物,他尤其喜欢那种横扫一片商店的快感。最近,他打算对D地的商店实行他疯狂的购物计划。D地的商业区就是一条街,这条街上有n个商店,哲哲打算进攻m次,每次扫荡第Li~Ri个商店,哲哲会把他经过的每个商店扫荡一空(换句话说,就是一个商店不会被算两次),因为连续地扫一片商店是很爽的,所以哲哲把一次扫荡的Happy值定义为所有连续的一段这次扫空的商店数的平方的和,已被扫空的不再计算,
如图:
现在你不经意间得知了哲哲的购物计划,而你需要求出哲哲获得的Happy值之和
【输入数据】
第一行为n和m,意义如描述之所示
接下来m行,每行两个数
Li Ri 表示哲哲第i次行动要扫荡第Li到第Ri个商店
【输出数据】
一行,包含一个数即为哲哲所获得的Happy值之和
【输入样例】
14 2
4 9
2 12
【输出样例】
49
【数据约定】
对于40%的数据,n,m<=1000
对于70%的数据,n,m<=50000
对于100%的数据,n,m<=300000,Li<=Ri
简化模型&考点:区间连续长度平方和
正解:并查集/线段树均可(线段树时间复杂度较高)
考场思路:第一反应线段树,但是没想出来,于是暴力40分
并查集代码:
1 // <shopping.cpp> - Sun Jun 12 08:04:25 2016 2 // This file is created by Lai Ruihang‘s black technology automatically. 3 // Copyright (C) 2016 ChangJun High School, Inc. 4 // I don‘t know what this program is. 5 6 #include <cstdio> 7 #include <cstdlib> 8 #include <iostream> 9 #include <algorithm> 10 #include <cstring> 11 #include <cmath> 12 #include <ctime> 13 #include <queue> 14 #include <string> 15 #include <map> 16 typedef long long ll; 17 const int MAXN = 300005; 18 using namespace std; 19 int n, m; 20 ll ans; 21 int fa[MAXN]; 22 bool book[MAXN]; 23 24 inline int gi() { 25 char c; 26 int sum = 0, f = 1; 27 c = getchar(); 28 while (c < ‘0‘ || c > ‘9‘) { 29 if (c == ‘-‘) 30 f = -1; 31 c = getchar(); 32 } 33 while (c >= ‘0‘ && c <= ‘9‘) { 34 sum = sum * 10 + c - ‘0‘; 35 c = getchar(); 36 } 37 return sum * f; 38 } 39 40 int main() { 41 freopen("shopping.in", "r", stdin); 42 freopen("shopping.out", "w", stdout); 43 n = gi(); 44 m = gi(); 45 for (int i = 1; i <= n; i++) 46 fa[i] = i; 47 for (int i = 1; i <= m; i++) { 48 int l = gi(); 49 int r = gi(); 50 ll len = 0; 51 for (int j = l; j <= r; j++) { 52 if (fa[j] != j || (fa[j] == j && book[j] == 1)) { 53 ans += len * len; 54 len = 0; 55 int x = j; 56 j = fa[j]; 57 fa[x] = r; 58 if (j < r) 59 fa[j] = r; 60 } else { 61 len++; 62 fa[j] = r; 63 book[j] = 1; 64 } 65 } 66 ans += len * len; 67 } 68 printf("%lld", ans); 69 return 0; 70 }
线段树代码:
1 // <shopping.cpp> - Sun Jun 12 08:04:25 2016 2 // This file is created by Lai Ruihang‘s black technology automatically. 3 // Copyright (C) 2016 ChangJun High School, Inc. 4 // I don‘t know what this program is. 5 6 #include <cstdio> 7 #include <cstdlib> 8 #include <iostream> 9 #include <algorithm> 10 #include <cstring> 11 #include <cmath> 12 #include <ctime> 13 #include <queue> 14 #include <string> 15 #include <map> 16 typedef long long ll; 17 const int MAXN = 300005; 18 #define ls o * 2 19 #define rs o * 2 + 1 20 using namespace std; 21 int INF = 1; 22 int n, m; 23 int _min[3 * MAXN], set[3 * MAXN]; 24 int s[MAXN]; 25 ll ans; 26 27 inline int gi() { 28 char c; 29 int sum = 0, f = 1; 30 c = getchar(); 31 while (c < ‘0‘ || c > ‘9‘) { 32 if (c == ‘-‘) 33 f = -1; 34 c = getchar(); 35 } 36 while (c >= ‘0‘ && c <= ‘9‘) { 37 sum = sum * 10 + c - ‘0‘; 38 c = getchar(); 39 } 40 return sum * f; 41 } 42 43 void build(int o, int l, int r) { 44 if (l == r) { 45 _min[o] = INF; 46 set[o] = INF; 47 return; 48 } 49 int mid = (l + r) >> 1; 50 build(ls, l, mid); 51 build(rs, mid + 1, r); 52 _min[o] = INF; 53 } 54 55 void pushdown(int o, int l, int r) { 56 _min[ls] = min(_min[ls], _min[o]); 57 _min[rs] = min(_min[rs], _min[o]); 58 } 59 60 void update(int o, int l, int r, int x, int y, int val) { 61 if (l >= x && r <= y) { 62 _min[o] = min(_min[o], val); 63 return; 64 } 65 if (_min[o] != INF) 66 pushdown(o, l, r); 67 int mid = (l + r) >> 1; 68 if (x <= mid) 69 update(ls, l, mid, x, y, val); 70 if (y > mid) 71 update(rs, mid + 1, r, x, y, val); 72 } 73 74 void get_s(int o, int l, int r) { 75 if (l == r) { 76 s[l] = _min[o]; 77 return; 78 } 79 pushdown(o, l, r); 80 int mid = (l + r) >> 1; 81 get_s(ls, l, mid); 82 get_s(rs, mid + 1, r); 83 } 84 85 int main() { 86 freopen("shopping.in", "r", stdin); 87 freopen("shopping.out", "w", stdout); 88 for (int i = 1; i <= 30; i++) 89 INF <<= 1; 90 n = gi(); 91 m = gi(); 92 build(1, 1, n); 93 for (int i = 1; i <= m; i++) { 94 int l = gi(); 95 int r = gi(); 96 update(1, 1, n, l, r, i); 97 } 98 get_s(1, 1, n); 99 ll len = 0; 100 for (int i = 1; i <= n; i++) { 101 if (s[i] == INF) { 102 ans += len * len; 103 len = 0; 104 } else if (s[i] != s[i - 1]) { 105 ans += len * len; 106 len = 1; 107 } else 108 len++; 109 } 110 ans += len * len; 111 printf("%lld", ans); 112 return 0; 113 }
------------------------------------------------------------------------------------------------------------------------------------------------------------
T4:精彩比赛match
【题目描述】
D市最近要举办一场盛况空前的比赛,D市市民对此比赛都十分关心。这一系列比赛将所有选手分成了两组,每组有n人,比赛是在两个分属两组的选手之间进行的,主办方在这些人之中安排了m场比赛,由于每个人的实力不尽相同,市民们对每个人的关注度也是不尽相同的,自然的,市民对于在不同的人之间举行的比赛的关注度也不尽相同,而且可能有的比赛对观众完全没有吸引力。而身为主办方的哲哲自然希望在QZTV的黄金时段转播受关注度高的比赛,以获得较高的收视率。
但实际上转播比赛是要受日程的限制的,尽管哲哲很想将最精彩的比赛呈现给大家,但他的上司给他做出了如下规定:
1. 比赛是按第一组选手的编号顺序从1~n进行的
2. 主办方已经预先给两组选手按实力编了号,为了不使比赛双方的选手实力相差过大,被选出来转播的比赛只能是第一组的编号为L1~R1的和第二组的编号L2~R2的选手之间所进行的所有比赛(这里的L1,R1,L2,R2均可由哲哲自己来选定,当然,也可以一场都不播)
哲哲希望在满足上司规定的条件下安排若干场在黄金时段转播的比赛,使得这些比赛的关注度之和最大
【输入数据】
第一行两个数,为n,m,意义见描述
接下来m行,每行三个数
xi,yi,zi,表示在第一组的xi号和第二组的yi号选手之间安排了一场比赛,关注度为zi
需要注意的是,zi可能为负数,即这场比赛相当难看,播出了反而会降低收视率
【输出数据】
一行,仅一个数,即最大的选出的比赛关注度之和
【输入样例】
3 5
1 3 2
2 3 -3
2 2 3
3 2 -1
3 1 2
【输出样例】
4
【数据约定】
对于20%的数据,n<=10
对于50%的数据,n<=80
对于100%的数据,n<=300,m<=n^2,|zi|<=50000
简化模型&考点:最大子矩阵和
正解:DP最大子矩阵和
考场思路:完全没想到是个最大子矩阵和的裸题,当时只觉得是个二分图的匹配……但是并不清楚是什么匹配。尝试用O(n^4)的暴力,但是数组炸了,还不如O(n^6)的暴力
1 // <match.cpp> - Sun Jun 12 08:04:25 2016 2 // This file is created by Lai Ruihang‘s black technology automatically. 3 // Copyright (C) 2016 ChangJun High School, Inc. 4 // I don‘t know what this program is. 5 6 #include <cstdio> 7 #include <cstdlib> 8 #include <iostream> 9 #include <algorithm> 10 #include <cstring> 11 #include <cmath> 12 #include <ctime> 13 #include <queue> 14 #include <string> 15 #include <map> 16 typedef long long ll; 17 const int MAXN = 305; 18 using namespace std; 19 int INF = 1; 20 int n, m; 21 ll s[MAXN][MAXN], sum[MAXN][MAXN]; 22 ll ans; 23 24 inline int gi() { 25 char c; 26 int sum = 0, f = 1; 27 c = getchar(); 28 while (c < ‘0‘ || c > ‘9‘) { 29 if (c == ‘-‘) 30 f = -1; 31 c = getchar(); 32 } 33 while (c >= ‘0‘ && c <= ‘9‘) { 34 sum = sum * 10 + c - ‘0‘; 35 c = getchar(); 36 } 37 return sum * f; 38 } 39 40 inline void query(int up, int down) { 41 ll maxf = -INF; 42 ll maxsum = 0, x = 0; 43 for (int i = 1; i <= n; i++) { 44 ll t = sum[down][i] - sum[up - 1][i]; 45 if (t < 0) 46 maxf = max(maxf, t); 47 x += t; 48 if (x > maxsum) 49 maxsum = x; 50 else if (x < 0) 51 x = 0; 52 } 53 if (maxsum == 0 && maxf != -INF) 54 maxsum = maxf; 55 ans = max(ans, maxsum); 56 } 57 58 int main() {
以上是关于[2016.6.11] NOIP模拟题的主要内容,如果未能解决你的问题,请参考以下文章