我是比赛链接

A(AtCoder):平方不等式

思路(huas_wlq):
直接判断输出

#include <bits/stdc++.h>  /// 万能头文件(囊括了绝大多数的头文件,无需再定义每一个头文件)      using namespace std;int main(){int a, b, c;cin >> a >> b >> c;if(a * a + b * b < c * c) cout << "Yes";else cout << "No";return 0;
}

B(huas_wlq):阅读理解

思路1(huas_wlq):
将数字当字符串处理,统一读入反向输出。

#include <bits/stdc++.h>using namespace std;string s;int main(){cin >> s;for(int i = s.length() - 1; ~i; i --) {cout << s[i];}return 0;
}

思路2(huas_wlq):
通过除、模运算,每次取得数字最后一位输出。

#include <bits/stdc++.h>using namespace std;#define ll long long  /// 宏定义int main() {ll x;cin >> x;while(x) {  /// x 没有前导零cout << x % 10;  /// 取得最后一位数x /= 10;  /// 删除最后一位数}return 0;
}

C(huas_wlq):阴阳合同

知识点:
1776 神奇的数组 姐妹篇,基础dp + 思维,关于基础dp 部分请看这篇 题解。

思路(huas_wlq):
考虑数组每个位置的意义,对于dp数组 dp[ i ][ 1] 其意义为“前 i 个数在第 i 个数被选取的时候所能获得的最大值(若数组第二维是 0 则代表的是不选时的最大值),而本题中我们需要考虑中间的每一个数其必须被选取或者必须不被选取时的最大值。

对于一个特殊的指定位置,我们假设其为第 x 位,且其是一定要被选取的,那么其最大值就是 其被选取 且其左右两个位置 不被选取的最大值 的和故有 ans = a[ x ] + dp1[ x - 1 ][ 0 ] + dp2[ x + 1 ][ 0 ] (其中 a[ x ] 代表第 x 个物品的价值 ,而 dp1 数组 代表从前往后求得的当前位置选于不选的最大值, dp2 数组 则是从后往前求得的当前位置选于不选的最大值)。

同理在 x 必定不被选取时有:ans = a[ x ] + dp1[ x ][ 0 ] + dp2[ x ][ 0 ] 。

勘误(21.05.17)(指正:王磊):当 x 在不被选取的时候我们需要左右都求一下是选取的值大还是不被选取的值大,这与我们 dp[ i ][ 0 ] 的求法其实是一样的,所以直接求出当前值不选的从前往后最大值和从后往前最大值即可(利用从前往后和从后往前的两次 dp 求出对应位置前段和后的值之后相加即可)。

#include <bits/stdc++.h>using namespace std;const int N = 100009;  /// 定义数组长度int n, a[N], m;
int b[N][2], c[N][2];int main() {cin >> n >> m;for(int i = 1; i <= n; i ++) scanf("%d", a + i);for(int i = 1; i <= n; i ++) {  /// dp1b[i][0] = max(b[i - 1][0], b[i - 1][1]);b[i][1] = b[i - 1][0] + a[i];}for(int i = n; i; i --) {  /// dp2c[i][0] = max(c[i + 1][0], c[i + 1][1]);c[i][1] = c[i + 1][0] + a[i];}int x, p;while(m --) {scanf("%d%d", &x, &p);if(p) printf("%d\n", c[x][1] + b[x][1] - a[x]);else printf("%d\n", c[x][0] + b[x][0]);/// 上面的两个求解式子看起来和题解中的式子不一样,但实际上两种写法的效果是等价的(请读者画图自证)。     }return 0;
}

D(琉璃花社的猫朵):翻硬币的小游戏

题解(琉璃花社的猫朵):
本题是一个思维题,大致题意如下:

小明摆了一圈硬币,告诉你每个硬币是正面还是反面,然后两个人去翻转硬币,每次翻转都会将连续的处于同一面的所有硬币都翻过来,问你是先手先将所有硬币翻至同一面还是后手先将所有硬币翻至同一面。

对于这个问题,实现我们要知道硬币只有两面,且对于连续的处于同面的硬币我们无论翻的是这连续一段中的哪个位置都会将这一段完全翻转,所以可以做一个转化,即,假设这是一个由红蓝两种颜色构成的环,那么每次
操作就将其中一段颜色变成另一种颜色(如原来是红色的段就变蓝色),那么每次操作都必定会将其操作的那一段变成和它相邻的段一样的颜色,如果操作之后还没有获胜,那么该段就会和它相邻的两段合并成一段,那么整个红蓝相间的环的红蓝段的段数-2,如果整个环只剩下一段红色和一段蓝色那么接下来无论对哪一段进行操作都必定会获胜,所以该题只需要统计出来红蓝段数即可,也就是连续正面和连续反面的段数,接下来由于每次操作必定使段数-2,所以如果段数除以2是奇数,也就意味着先手必定进行最后一次操作,所以先手会获胜,如果段数除以2是偶数则后手会获胜,同时需注意,题目规定了当局面开始时所有硬币都在同一面时算先手获胜,所以对于段数为1时需要特判一下。

所以该题就是判断奇偶的题。

#include<iostream>
using namespace std;
const int N = 1e4+10;
int a[N];
int cnt;
int main()
{int n;int now;scanf("%d",&n);for(int i = 0;i<n;i++){scanf("%d",&a[i]);if(i == 0)now = a[i];//记录第一段的面else if(now != a[i]){cnt++;//统计段数now = a[i];//记录下一段的面}}if(now != a[0])cnt++;//如果首尾不能合并则段数加1if(cnt == 0 || (cnt/2)%2)printf("Alan\n");//判断段数除2的结果的奇偶性     else printf("Gino\n");return 0;
}

E(the_xin):迷宫大师

知识点:
bfs(广度优先搜索)。

思路(huas_wlq):
注意到本题的数据范围比较小,如果枚举出每个点求出距离其最远的点的距离那么就可以通过判断答案的大小关系而得到最终的答案。

而对于一个图来说,得到图中所有可以达到的点到指定点的距离我们可以通过 bfs 来求得,而 bfs 时间复杂度是地图的大小。结合上面提到的枚举每一个点我们可以求得时间复杂度为:T * (n * m) * (n * m) <= 2.43e7 < 2e8,所以暴力枚举搜索的时间复杂度是可以接受的。

#include <bits/stdc++.h>using namespace std;#define ll long longtypedef pair<int, int> pii;  /// 声明一个类型(用 pii 代替前面繁琐的命名方式
/// pair 是 C++ 提供的一个存储数对的变量类型,内部重载了很多常用的方法(建议百度了解下)const int N = 32;   /// 数组范围int n, m;
char a[N][N];struct node {   /// 用来存储答案int x;   /// 步数pii one, two;   /// 起点的坐标和终点的坐标int operator < (const node &p) const {if(x != p.x) return x < p.x;  /// 步数越大越好if(one != p.one) return one > p.one;  /// 坐标(字典序)越小越好return two > p.two;}
}no;int amax;  /// 存储最大的步长
priority_queue<node> pq;  /// 结构体优先队列,用来存储所有的可行解
/// 优先队列是 STL 提供的一种类二叉堆的数据结构,其(默认)保证队头元素一定是队内最大元素,
/// 其插入和删除的时间复杂度都为 log 级别int vis[N][N];  /// 标记当前坐标走过与否
pii pi;
queue<pii> qu;  /// 记录第一次被走过的位置坐标
int tx[] = {0, 1, 0, -1, 0};
void bfs(int xx, int yy) {int x, y;vis[xx][yy] = 1;qu.push({xx, yy});while(!qu.empty()) {pi = qu.front();  qu.pop();for(int i = 1; i < 5; i ++) {x = pi.first + tx[i];  y = pi.second + tx[i - 1];if(!x || !y || x > n || y > m || a[x][y] == '#' || vis[x][y]) continue;  /// 越界或者“撞墙”        vis[x][y] = vis[pi.first][pi.second] + 1;qu.push({x, y});  /// 第一次遍历到的结点入队if(vis[x][y] >= amax) amax = vis[x][y], pq.push({vis[x][y], {xx, yy}, {x, y}});                    /// 作为可行答案之一入队,判断是为了删除不可能的解(步数太少),不删会超时。}}
}
int main(){int t;  cin >> t;while(t --) {cin >> n >> m;for(int i = 1; i <= n; i ++) scanf(" %s", a[i] + 1);for(int i = 1; i <= n; i ++){for(int j = 1; j <= m; j ++) {   /// 枚举每个点if(a[i][j] == '.') {  /// 从有路的点出发才有意义bfs(i, j);memset(vis, 0, sizeof(vis));}}}no = pq.top();  /// 队头即为最优解cout << no.one.first << ' ' << no.one.second << ' ' << no.two.first<< ' ' << no.two.second << ' ' << no.x - 1 << endl;while(!pq.empty()) pq.pop();  amax = 0;  /// 清空队列并重置最长路}return 0;
}

F(huaszzh):小孩儿的问题

思路1(huaszzh):
这个数据是 1e12 ,我们直接暴力会超时,此时我们只需要将数字拼接起来的话就能做到 1e6 的效果,这样我们就只需要暴力枚举1e6即可。(时间复杂度 sqrt(n) )

/// huaszzh
#include<iostream>using namespace std;
typedef long long ll;
int main() {ll n;cin>>n;ll ans=0;for (ll i=1; ; i++) {string s=to_string(i)+to_string(i); //将数字合并ll t=stoll(s); //转成llif (t>n) {cout<<i-1<<"\n";return 0;}}return 0;
}

思路2(huas_wlq):
我们注意到,对于任何一个“对称的数”都可以找到一个 x 使得 xx 是等于这个数的且对于所有的 x 符合上述要求,那么一定会有 x - 1 也符合上述要求(在 x - 1 不小于 0 的时候)。

也就是说,假设我们的答案是 ans 那么对于区间 [1, ans] 之间的所有数都会符合上述要求,那么对于整个区间 [1, n] 它是 满足二分性质 的(对于某个 check 函数而言,区间两侧的真假性不相同),所以我们可以 二分 求解。(时间复杂度 log(n) )

#include <bits/stdc++.h>using namespace std;#define ll long longll n;int ck(int x) {  /// 求得 xx 是否小于等于 nll sum = x, m = x;while(x) {   /// 循环的次数取决于 x 的位数x /= 10;sum *= 10;}sum += m;return sum <= n;
}
int main() {cin >> n;int l = 1, r = 1e9;while(l < r) {  /// 二分答案int mid = r + l + 1 >> 1;if(ck(mid)) l = mid;else r = mid - 1;}cout << l;return 0;
}

G(huas_wlq、huaszq):玩具工厂

思路(huas_wlq):
题目抽象:我们每次可以选取 01 串中连续的一段将其删去,然后将被删除段的左右点在连接在一起继续进行删除操作,最少删几次后可以吧整个串删空。

由于每次选取的是连续的一段区间,我们不妨将连续的区间都缩小为一个点,即我们可以得到一个标准的、没有连续元素的 01 串。对于没有连续元素的 01 串来说,我们如果要将其删空那么是一定不会去选取左右端点进行操作的(除非仅剩端点的存在),这是因为,当我们删除掉中间的某一个 0 或者 1 之后,其左右两边的数字一定会相同,从而就相当于同时删去了两个区间,而端点处的点显然就没有这个性质了。

其实我们还有一种思考方式,即对于一个标准的 01 串,我们只需要删除掉其中所有的 0 或者 1 的位置,最后剩下的一定是一个“纯色”的串,直接就可以删掉。所以就不需要上面的模拟了,只需要数出不同的 01 的段数将其除二加一即可(如果 1 的段数多我们就删零,反之则删 1 )。

代码:下面是后一种思路的代码,模拟的代码就不贴了(我不会告诉你是因为我没写才不贴的)

#include <bits/stdc++.h>using namespace std;int main(){int sum = 1;  /// 初值为 1 (至少有一段)string s;cin >> s;for(int i = 1; i < s.length(); i ++) {  /// 计算 01 串的段数      if(s[i] != s[i - 1]) sum ++;}cout << sum / 2 + 1;return 0;
}

H(duoduo):组成数字

思路(duoduo、huas_wlq):
大家还记得上次周测的签到题吗?我们讨论一个区间在取 k 个数的条件下的最大值和最小值的时候发现,对于这个最值区间中的每一个数我们都可以用 k 个数来表示出来,所以我们可以枚举被选取的数的个数(考虑到题目中给出的范围,我们从 1 开始枚举最多枚举到 1e6 的时候就可以保证一定枚举过所有的可能了),然后考虑在这个条件下是否能组成指定数字,选取其中的最大和最小值作为答案即可。

#include <bits/stdc++.h>using namespace std;int main(){int l, r, w;cin >> l >> r >> w;int ans1 = 0, ans2 = 0;  /// ans1 存的是最小值for(int i = 1; i <= 1e6; i ++) {if(l * i <= w && r * i >= w) {  /// 可以证明,这里的乘积不会爆 int   if(ans1 == 0) ans1 = i;else ans2 = i;}}if(ans1 == 0) cout << "unsolvable";else if(ans2 == 0) cout << ans1 << ' ' << ans1;else cout << ans1 << ' ' << ans2;return 0;
}

I(huas_chainz):找三元组

思路(the_xin、huas_wlq):
其实对于 c 的要求是很低的(正整数),那么在不考虑 c 的存在的情况下,题目就变为了:求出所有的 a * b < n (为了给 c 留空间所以不取等号)。

然后一切都变得简单了起来,直接两层 for 循环枚举所有可能的 a、b 的值之后累加即可(时间复杂度 e * n (这里的 e 是自然对数),当然,第二层可以用数学公式优化成 O(1) 的时间复杂度(甚至直接一次全优化掉包括第一层也是可以的),这样整体时间复杂度就会是 n )。

#include <bits/stdc++.h>using namespace std;int main(){int n;cin >> n;int ans = 0;for(int i = 1; i < n; i ++)for(int j = 1; j < (n + i - 1) / i; j ++)ans ++;cout << ans;return 0;
}

(完)

湖南文理学院第十六届程序设计竞赛_题解相关推荐

  1. 训练实录 | 湖南大学第十六届程序设计竞赛

    湖南大学第十六届程序设计竞赛 传送门 A - Triangles solved by Micky. 00:38:55(+2) 题意: 水题,给三个点的坐标,判断是(钝角,锐角,直角,非)三角形. #i ...

  2. 文远知行杯广东工业大学第十六届程序设计竞赛ABEFHI(记录)

    文远知行杯广东工业大学第十六届程序设计竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ大学ACM校赛新生赛是面向ACM/ICPC/CCPC/区域赛校队选手,巩固经典专 ...

  3. 文远知行杯广东工业大学第十六届程序设计竞赛(题解)

    文远知行杯广东工业大学第十六届程序设计竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ A:思维题 #include<bits/stdc++.h> usi ...

  4. 2022年 文远知行杯 GDUT 第十六届程序设计竞赛(同步赛) 部分题解

    今年做出来的题还没去年多,看来是题目质量高了(我又变菜了). 同步赛地址:文远知行杯广东工业大学第十六届程序设计竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJB B ...

  5. 湖南大学第十六届程序设计竞赛 B Yuki with emofunc and playf 同余最短路

    传送门 文章目录 题意: 思路: 题意: 初始有一个数111,你每次可以将其∗10*10∗10或者+(x−1)+(x-1)+(x−1),现在给你xxx,问最少经过多少步能到达nnn. 1≤n≤1e6, ...

  6. 牛客 —— 湖南大学第十六届程序设计竞赛(重现赛)

    文章目录 A Triangles B Yuki with emofunc and playf D Queuing F Team G Binbin's string I Binbin and Balls ...

  7. 文远知行杯广东工业大学第十六届程序设计竞赛 E爬塔

    题目描述 Alice最近迷上了杀怪爬塔的游戏,在塔中有n层关卡,在通过第i层关卡后Alice会走上第i+1层.每个关卡中可能会获得女神的祝福或者遇到怪物.如果得到女神的祝福,Alice生命值会+1,如 ...

  8. 2018北京师范大学第十六届程序设计竞赛决赛

    A   塞特斯玛斯塔 > 25987787 1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath&g ...

  9. 文远知行杯广东工业大学第十六届程序设计竞赛错题笔记

    目录 官网链接 A 区间最大值 F 一个很大的数 I V字钩爪 官网链接 A 区间最大值 题目描述 长度为 n 的数组 a,下标从1开始,定义 a[i]=n%i 有 m 组询问 {L,R},求 max ...

最新文章

  1. MySQL长途售票系统_PHP+MySQL长途客用汽车票订票系统的设计与实现
  2. 计算机的硬盘和光盘数,硬盘和光盘属于什么媒体
  3. 东京见闻:快速走红日本市场 阿里云的三大秘密
  4. ESP8266的MQTT客户端搭建教程(基于NONS_SDK_v2.0)
  5. 【全】Docker(二)-在Docker中部署Nginx实现负载均衡视频教程
  6. 当Java 8 Streams API不够用时
  7. 鲲鹏920 centos7 postgresql12 postgis2.5.4编译
  8. RTOS原理与实现09:事件标志组实现
  9. SQL 取空格右边的字符_从零学会SQL,第2关
  10. KeyMob聚合致力于为广大开发者及广告聚合服务
  11. 物质为何能在虚空粒子海中存在
  12. 【ACM-ICPC 2018 南京赛区网络预赛】Magical Girl Haze【分层图】
  13. JDBC原生连接与连接池介绍
  14. WebRoot和Web-Info区别
  15. 4步用Python搞定客户细分!
  16. 极域教室老师版,控制同学电脑
  17. Java项目源码SSM宿舍管理系统|寝室
  18. 【ARM裸机s5pv210 】芯片初始化
  19. PLSQL连接Oracle:ORA-12154: TNS: 无法解析指定的连接标识符
  20. 【深度域适配】一、DANN与梯度反转层(GRL)详解

热门文章

  1. OKhttp+Gson实现从网络上获取最新新闻
  2. linux c 编译 未定义的引用,c – Linux makefile中的未定义引用
  3. (自)协方差矩阵与互协方差矩阵简介
  4. 史上最全Maven教程(四)
  5. MOSFET的SOA或者ASO是什么?
  6. 获取当前日期的年月日
  7. zigzag算法详解
  8. GO基础---for循环
  9. Python字符串的索引与切片
  10. 企业微信客户端通过jsapi调起微信扫码提示40093:jsapi签名错误