sc2017新高二&高一模拟赛7 总结
2017-08-16 10:22
316 查看
前言:三道大水题。。。
wyz有2n张纸牌,点数分别为1到2n。wyz要和你玩一个游戏,这个游戏中,每个人都会分到n张卡牌。游戏一共分为n轮,每轮你们都要出一张牌,点数大者获胜。
不自量力的wyz觉得你很菜,于是每轮他都会先于你出牌,你可以根据他出的牌来做决策。
游戏开始了,你拿到了你的牌,你现在想知道,你最多能够获胜几轮?
对于32.5%的数据,保证1<=n<=100
对于100%的数据,保证1<=n<=50,000
保证数据的合法性,即你即不会拿到重复的牌,又不会拿到超出点数范围的牌。
第2行到第n+1行每行一个正整数a[i],表示你的第i张牌的点数。
1
4
我们将手牌按小到大排序,然后用自己的牌去吃对方的牌,由于单调递增,所以时间O(n)。
wyz有2个容量分别为n单位、m单位的没有刻度的杯具。wyz有t分钟可以摆弄他的杯具。每一分钟,他都可以做下面4件事中的任意一件:
(1)用水龙头放满一个杯具。
(2)倒空一个杯具。
(3)把一个杯具里的水倒到另一个杯具里,直到一个杯具空了或者另一个杯具满了。(看哪种情况先发生)
(4)什么都不做。
wyz希望最后能获得d个单位的水,假设最后两个杯具中水量的总和为x,那么他的不开心度就为|d-x|。
现在你想知道,wyz的不开心度最小是多少。
对于10%的数据,保证t=1
对于20%的数据,保证t<=2
对于40%的数据,保证t<=4
对于100%的数据,保证1<=n,m<=100,1<=t<=100,1<=d<=200
或者直接无脑宽搜,哪种都好,n才100,时间完全不是问题。
然而我考试时闲得无聊,两种方法都写了,还拿来拍了半天。。。
wyz还在后院里建了许多栅栏。有n个平行于y轴的栅栏a1..an,表示挡在(ai,0)到(ai,B)之间。有m个平行于x轴的栅栏b1..bn,表示挡在(0,bi)到(A,bi)之间。这样,平面被划成了(n+1)*(m+1)块辣鸡的活动区域。
为了方便辣鸡的活动,wyz现在要去掉某些栅栏的一部分,使得每一块活动区域都连通。
同时,每次修改栅栏只能去掉从某个交点到另一个交点的一整段栅栏。举(打)个比(栗)方(子):
原来是这样的布局,经过修改可以变成这样:
现在,wyz想知道,要使得每一块辣鸡活动区域都联通,最少需要去掉多少长度的栅栏。
对于10%的数据,A,B<=1000,n,m<=20
对于30%的数据,A,B<=1000,000,n*m<=25,000
对于40%的数据,n*m<=250,000
对于50%的数据,n*m<=4,000,000
对于100%的数据,1<=A,B<=1000,000,000,1<=n,m<=25,000
数据保证 0 < a[i] < A,0 < b[i] < B
第2行到第n+1行,每行1个正整数,第i+1行的数描述了a[i]。
第n+2行到第n+m+1行,每行1个正整数,第n+i+1行的数描述了b[i]。
2
5
10
6
4
11
3
题目很明显是在求最小生成树。
转化就像下图一样:
原图中的横着的栅栏就是竖着的边,竖着的栅栏就是横着的边,每一横排、竖排的边权一样。破坏栅栏就是在连边。如果直接做Kruskal肯定超时,然而第一次做这题的时候,脑壳坏了,想不到该怎么搞,结果就直接来了。甚至我想到了排序后必然是一段一段的,但是判环还是没有想到点上。
那时随便在草稿上画了一下,发现一开始的情况和后来不太一样,觉得没什么规律可循。其实就是有规律可循啊。。。
我们发现每次必然加整一行或列,出现环就会少加一部分,行少加是受到列的影响,列也一样。行一开始整行加,后来有了两列一行后,再整行加就会有环,只能少加一个,后面随着列的增加,行越加越少,每次少一,这就发现了规律。列也是一样的(画个图比较好理解)。
于是直接将读入转成边排序,然后按着规律加边算答案。
再见,超时。
黑暗。
纸牌
题目描述
纸牌选手wyz喜欢玩纸牌。wyz有2n张纸牌,点数分别为1到2n。wyz要和你玩一个游戏,这个游戏中,每个人都会分到n张卡牌。游戏一共分为n轮,每轮你们都要出一张牌,点数大者获胜。
不自量力的wyz觉得你很菜,于是每轮他都会先于你出牌,你可以根据他出的牌来做决策。
游戏开始了,你拿到了你的牌,你现在想知道,你最多能够获胜几轮?
对于32.5%的数据,保证1<=n<=100
对于100%的数据,保证1<=n<=50,000
保证数据的合法性,即你即不会拿到重复的牌,又不会拿到超出点数范围的牌。
输入格式
第一行1个正整数n。第2行到第n+1行每行一个正整数a[i],表示你的第i张牌的点数。
输出格式
一行一个整数表示你最多能够获胜的轮数。输入样例
21
4
输出样例
1题解(贪心+单调)
这题就是什么塞翁失马,应该是田忌赛马的加强版。我们将手牌按小到大排序,然后用自己的牌去吃对方的牌,由于单调递增,所以时间O(n)。
代码
#include <cstdio> #include <cstdlib> #include <cmath> #include <iostream> #include <cstring> #include <algorithm> #define N 100010 using namespace std; int n, x, ans; int a , b ; bool vis ; int main(){ scanf("%d", &n); for(int i = 1; i <= n; i++){ scanf("%d", &x); vis[x] = true; } for(int i = 1; i <= 2*n; i++){ if(vis[i]) a[++a[0]] = i; else b[++b[0]] = i; } for(int i = 1, j = 1; i <= n; i++){ for(; j <= n; j++) if(a[j] > b[i]){ ans ++; j ++; break; } } printf("%d\n", ans); return 0; }
杯具
题目描述
杯具选手wyz喜欢玩杯具。wyz有2个容量分别为n单位、m单位的没有刻度的杯具。wyz有t分钟可以摆弄他的杯具。每一分钟,他都可以做下面4件事中的任意一件:
(1)用水龙头放满一个杯具。
(2)倒空一个杯具。
(3)把一个杯具里的水倒到另一个杯具里,直到一个杯具空了或者另一个杯具满了。(看哪种情况先发生)
(4)什么都不做。
wyz希望最后能获得d个单位的水,假设最后两个杯具中水量的总和为x,那么他的不开心度就为|d-x|。
现在你想知道,wyz的不开心度最小是多少。
对于10%的数据,保证t=1
对于20%的数据,保证t<=2
对于40%的数据,保证t<=4
对于100%的数据,保证1<=n,m<=100,1<=t<=100,1<=d<=200
输入格式
第一行4个整数n、m、t、d,分别表示两个杯具的容量、时间限制以及期望值。输出格式
一行一个整数表示wyz的最小不开心度。输入样例
7 25 2 16输出样例
9题解(dp/bfs)
我都不想说这题了,话说这不是普及组难度吗?一个很简单的dp,以时间为阶段,记录两个杯子分别的水量是否可以到达,f[i][j][k]=true/false。然后直接推,最后找答案。或者直接无脑宽搜,哪种都好,n才100,时间完全不是问题。
然而我考试时闲得无聊,两种方法都写了,还拿来拍了半天。。。
代码(dp)
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <cstdlib> #include <iostream> #define N 111 #define oo 0x7fffffff using namespace std; int n, m, T, D, ans = oo; bool f ; int main(){ scanf("%d%d%d%d", &n, &m, &T, &D); f[0][0][0] = true; for(int i = 0; i < T; i++) for(int c1 = 0; c1 <= n; c1++) for(int c2 = 0; c2 <= m; c2++){ if(!f[i][c1][c2]) continue; f[i+1][c1][c2] = true; f[i+1][0][c2] = true; f[i+1][c1][0] = true; f[i+1] [c2] = true; f[i+1][c1][m] = true; if(n - c1 >= c2) f[i+1][c1+c2][0] = true; else f[i+1] [c2-n+c1] = true; if(m - c2 >= c1) f[i+1][0][c1+c2] = true; else f[i+1][c1-m+c2][m] = true; } for(int c1 = 0; c1 <= n; c1++) for(int c2 = 0; c2 <= m; c2++){ if(!f[T][c1][c2]) continue; ans = min(ans, abs(c1+c2-D)); } printf("%d\n", ans); return 0; }
代码(bfs)
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <cstdlib> #include <iostream> #define N 111 #define oo 0x7fffffff using namespace std; int n, m, T, D, ans = oo; bool f ; struct Data{ int t, c1, c2; Data() {} Data(int _t, int _c1, int _c2):t(_t), c1(_c1), c2(_c2) {} }q[N*N*N]; int head, tail; int main(){ scanf("%d%d%d%d", &n, &m, &T, &D); q[0] = Data(0, 0, 0); f[0][0][0] = true; while(head <= tail){ int i = q[head].t, c1 = q[head].c1, c2 = q[head].c2; head ++; if(i == T) continue; if(!f[i+1][c1][c2]){ q[++tail] = Data(i+1, c1, c2); f[i+1][c1][c2] = true; } if(!f[i+1][0][c2]){ q[++tail] = Data(i+1, 0, c2); f[i+1][0][c2] = true; } if(!f[i+1][c1][0]){ q[++tail] = Data(i+1, c1, 0); f[i+1][c1][0] = true; } if(!f[i+1] [c2]){ q[++tail] = Data(i+1, n, c2); f[i+1] [c2] = true; } if(!f[i+1][c1][m]){ q[++tail] = Data(i+1, c1, m); f[i+1][c1][m] = true; } if(n - c1 >= c2){ if(!f[i+1][c1+c2][0]){ q[++tail] = Data(i+1, c1+c2, 0); f[i+1][c1+c2][0] = true; } } else{ if(!f[i+1] [c2-n+c1]){ q[++tail] = Data(i+1, n, c2-n+c1); f[i+1] [c2-n+c1] = true; } } if(m - c2 >= c1){ if(!f[i+1][0][c1+c2]){ q[++tail] = Data(i+1, 0, c1+c2); f[i+1][0][c1+c2] = true; } } else{ if(!f[i+1][c1-m+c2][m]){ q[++tail] = Data(i+1, c1-m+c2, m); f[i+1][c1-m+c2][m] = true; } } } for(int c1 = 0; c1 <= n; c1++) for(int c2 = 0; c2 <= m; c2++){ if(!f[T][c1][c2]) continue; ans = min(ans, abs(c1+c2-D)); } printf("%d\n", ans); return 0; }
辣鸡
题目描述
wyz在后院养了许多辣鸡。wyz的后院可以看成一个A*B的矩形,左下角的坐标为(0,0),右上角的坐标为(A,B)。wyz还在后院里建了许多栅栏。有n个平行于y轴的栅栏a1..an,表示挡在(ai,0)到(ai,B)之间。有m个平行于x轴的栅栏b1..bn,表示挡在(0,bi)到(A,bi)之间。这样,平面被划成了(n+1)*(m+1)块辣鸡的活动区域。
为了方便辣鸡的活动,wyz现在要去掉某些栅栏的一部分,使得每一块活动区域都连通。
同时,每次修改栅栏只能去掉从某个交点到另一个交点的一整段栅栏。举(打)个比(栗)方(子):
原来是这样的布局,经过修改可以变成这样:
现在,wyz想知道,要使得每一块辣鸡活动区域都联通,最少需要去掉多少长度的栅栏。
对于10%的数据,A,B<=1000,n,m<=20
对于30%的数据,A,B<=1000,000,n*m<=25,000
对于40%的数据,n*m<=250,000
对于50%的数据,n*m<=4,000,000
对于100%的数据,1<=A,B<=1000,000,000,1<=n,m<=25,000
数据保证 0 < a[i] < A,0 < b[i] < B
输入格式
第一行4个正整数A、B、n、m,描述了后院的大小和两种栅栏的数目。第2行到第n+1行,每行1个正整数,第i+1行的数描述了a[i]。
第n+2行到第n+m+1行,每行1个正整数,第n+i+1行的数描述了b[i]。
输出格式
一行一个整数表示需要去掉的栅栏的最小长度总和。输入样例
15 15 5 22
5
10
6
4
11
3
输出样例
44题解(MST+找规律)
这是题原题。。。题目很明显是在求最小生成树。
转化就像下图一样:
原图中的横着的栅栏就是竖着的边,竖着的栅栏就是横着的边,每一横排、竖排的边权一样。破坏栅栏就是在连边。如果直接做Kruskal肯定超时,然而第一次做这题的时候,脑壳坏了,想不到该怎么搞,结果就直接来了。甚至我想到了排序后必然是一段一段的,但是判环还是没有想到点上。
那时随便在草稿上画了一下,发现一开始的情况和后来不太一样,觉得没什么规律可循。其实就是有规律可循啊。。。
我们发现每次必然加整一行或列,出现环就会少加一部分,行少加是受到列的影响,列也一样。行一开始整行加,后来有了两列一行后,再整行加就会有环,只能少加一个,后面随着列的增加,行越加越少,每次少一,这就发现了规律。列也是一样的(画个图比较好理解)。
于是直接将读入转成边排序,然后按着规律加边算答案。
再见,超时。
代码
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cmath> #include <iostream> #define N 25010 using namespace std; typedef long long LL; LL A, B, a , b , ans; int n, m, Rcnt, Lcnt; struct Data{ LL len, id; bool operator < (const Data& Q)const {return len < Q.len;} }fen[N<<1]; int main(){ scanf("%lld%lld%d%d", &A, &B, &n, &m); for(int i = 1; i <= n; i++) scanf("%lld", &a[i]); for(int i = 1; i <= m; i++) scanf("%lld", &b[i]); a[0] = 0; a[n+1] = A; b[0] = 0; b[m+1] = B; sort(a, a+n+2); sort(b, b+m+2); for(int i = 1; i <= n+1; i++) fen[i].len = a[i] - a[i-1], fen[i].id = 0; for(int i = 1; i <= m+1; i++) fen[i+n+1].len = b[i] - b[i-1], fen[i+n+1].id = 1; sort(fen+1, fen+n+m+3); for(int i = 1; i <= n + m + 2; i++){ if(!fen[i].id){ if(Rcnt >= 2 && Lcnt >= 1) ans += fen[i].len * (m - Rcnt + 1); else ans += fen[i].len * m; Lcnt ++; } else{ if(Lcnt >= 2 && Rcnt >= 1) ans += fen[i].len * (n - Lcnt + 1); else ans += fen[i].len * n; Rcnt ++; } } printf("%lld\n", ans); return 0; }
总结
这次比赛太水了,有十几个人AK,只有蒟蒻我还在水总结。黑暗。
相关文章推荐
- sc2017新高二&高一模拟赛7 总结
- sc2017新高二&高一模拟赛3 总结
- sc2017新高二&高一模拟赛2 总结
- sc2017新高二&高一模拟赛2 总结
- sc2017新高二&高一模拟赛6 总结
- sc2017新高二&高一模拟赛9 总结
- sc2017新高二&高一模拟赛1 总结
- sc2017新高二&高一模拟赛8 总结
- sc2017新高二&高一模拟赛4 总结
- sc2017新高二&高一模拟赛5 总结
- 高二&高一&初三模拟赛25 总结
- sc2017新高二&高一模拟赛10 总结
- 高二&高一&初三模拟赛14 总结
- 高二&高一&初三模拟赛24 总结
- 高二&高一模拟赛12 总结
- 高二&高一&初三模拟赛25 总结
- 高二&高一&初三模拟赛27 总结
- 高二&高一&初三模拟赛17 总结
- sc2017新高二&初三模拟赛11 总结
- 高二&高一&初三模拟赛16 总结