今年题目难度有较大提升,总体与往年类似,数学题居多。以下为我通过的部分题解。

赛题链接:http://acm.xidian.edu.cn/contest.php?cid=1053

A - 上帝视角

我也没去过澳门赌场,不熟悉什么筹码之类。看完题有点懵,但毕竟是签到题。

题目大概是隐含了总筹码数量相同这一条件,然后每个人开始的筹码都是一样的。给你一组每个人手上筹码的局面,然后有q组询问,让你判断现在局面是否合法,其中一个人赢了还是输了。

比较简单,废话不多说直接上代码:

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;ll arr[1010], qi[1010];
int main()
{int n, m, q;ll total = 0;cin>>n;for(int i=0;i<n;i++)cin>>arr[i], total += arr[i];cin>>q;for(int i=0;i<q;i++)cin>>qi[i];if(total%n)cout<<"you ren chu qian?\n";else {total /= n;for(int i=0;i<q;i++)if(arr[qi[i]-1]>total) cout<<"jian hao jiu shou!\n";else if(arr[qi[i]-1]<total) cout<<"ji shi zhi sun!\n";else cout<<"wei shi bu wan!\n";}return 0;
}

View Code

B - Shocking! Two Acmer Doing This In The Lab!

感觉太复杂了,一直没做,AC了再来更新吧。大概就是一个思维题。

C - XY之说走就走的旅行

简单的BFS,开始题目看错了,以为求min(disA+disB),交上去WA了一发,再看题发现是求min(max(disA, disB));

因为偷懒用一个数组存(i,j)到两地的最大距离,不明不白WA了半天。。。思考问题一定要考虑周全啊!!!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;int n, m;
char mp[220][220];
int s1x, s1y, s2x, s2y, k;
bool vis[220][220];
int dis[220][220];
const int dx[]={0, 0, 1, -1};
const int dy[]={1, -1, 0, 0};
struct node{int x, y;int step;node(int xx=0, int yy=0, int s=0):x(xx), y(yy), step(s){}
} sta[220];
void bfs(int t, int x, int y)
{vis[x][y] = 1;queue<node> q;q.push(node(x, y, 0));while(q.size()) {node now = q.front(); q.pop();for(int i=0;i<4;i++) {int nx = now.x+dx[i];int ny = now.y+dy[i];if(nx>=0 && nx<n && ny>=0 && ny<m && !vis[nx][ny] && mp[nx][ny]!='#') {vis[nx][ny] = 1;if(mp[nx][ny]=='P') {if(t==0) dis[nx][ny] = now.step+1;else if(dis[nx][ny])dis[nx][ny] = max(now.step+1, dis[nx][ny]);}q.push(node(nx, ny, now.step+1));}}}
}
int main()
{while(cin>>n>>m){k = 0;getchar();for(int i=0;i<n;i++) {scanf("%s", mp[i]);for(int j=0;mp[i][j];j++)if(mp[i][j]=='P') sta[k].x = i, sta[k++].y=j;else if(mp[i][j]=='X') s1x = i, s1y = j;else if(mp[i][j]=='Y') s2x = i, s2y = j;}memset(dis, 0, sizeof(dis));memset(vis, 0, sizeof(vis));bfs(0, s1x, s1y);memset(vis, 0, sizeof(vis));bfs(1, s2x, s2y);int x, ans = 10000000;for(int i=0;i<k;i++)if(dis[sta[i].x][sta[i].y] && dis[sta[i].x][sta[i].y]<ans)x = i, ans = dis[sta[x].x][sta[x].y];cout<<sta[x].x+1<<' '<<sta[x].y+1<<endl;}return 0;
}

View Code

D - 武举考试安排表

这题难点在于读懂题目,然后就是要打表找规律。直白说比赛安排表类似一个数独,添上一行123...N的表头代表队员编号的话,那么整个表就有N行N列。我们要使每行每列都有1~N,并且要找到一个字典序最小的方案。

第一天我很天真地以为,简单把123...N的排列每次循环左移就能得到字典序最小的安排表。WA了三次后,在纸上排一遍发现还能有更优的排法,排表过程中要用到dfs,复杂度O(22N),就扔到一边没管了。

过了两天根据Wu找的规律几分钟写了代码就直接AC了,哈哈哈。预处理n=10的安排表,查询O(1),总的时间复杂度O(220+T)。

#include<iostream>
#include<cstdio>
using namespace std;
int ans[1024][1024];
const int num[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048};
void pre()
{ans[0][0] = ans[1][1] = 1;ans[0][1] = ans[1][0] = 2;int s = 2;while(s<1024) {for(int i=s;i<2*s;i++)for(int j=0;j<s;j++)ans[i][j] = s+ans[i-s][j];for(int i=0;i<s;i++)for(int j=s;j<2*s;j++)ans[i][j] = s+ans[i][j-s];for(int i=s;i<2*s;i++)for(int j=s;j<2*s;j++)ans[i][j] = ans[i-s][j-s];s *= 2;}
}
int main()
{pre();for(int i=0;i<32;i++) {for(int j=0;j<32;j++)printf("%2d ", ans[i][j]);cout<<endl;}int T; cin>>T;int n, m, x;while(T--){scanf("%d %d %d", &n, &m, &x);if(m<1||m>num[n]||x<1||x>num[n]-1)cout<<"Wrong Query!\n";else {cout<<ans[x][m-1]<<endl;}}return 0;
}

View Code

E - 最后一个

一眼扫去这不就是Nim博弈吗?然后就快速写了个Nim和,交上去就WA了。再细看发现结束的规则不一样,取走最后的石子者为败家。想了半天还是不太会博弈,既然状态有限,就写了记忆化搜索,调试好样例交上就AC了。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int s[7][7][7][7][7][7];  // s=0 败  s=1 胜
int solve(int a, int b, int c, int d, int e, int f)
{if(a+b+c+d+e+f==1) return 0;if(s[a][b][c][d][e][f]!=-1)return s[a][b][c][d][e][f];for(int i=1;i<=a;i++)if(solve(a-i, b, c, d, e, f)==0) return s[a][b][c][d][e][f]=1;for(int i=1;i<=b;i++)if(solve(a, b-i, c, d, e, f)==0) return s[a][b][c][d][e][f]=1;for(int i=1;i<=c;i++)if(solve(a, b, c-i, d, e, f)==0) return s[a][b][c][d][e][f]=1;for(int i=1;i<=d;i++)if(solve(a, b, c, d-i, e, f)==0) return s[a][b][c][d][e][f]=1;for(int i=1;i<=e;i++)if(solve(a, b, c, d, e-i, f)==0) return s[a][b][c][d][e][f]=1;for(int i=1;i<=f;i++)if(solve(a, b, c, d, e, f-i)==0) return s[a][b][c][d][e][f]=1;return s[a][b][c][d][e][f]=0;}
int arr[6];
int main()
{memset(s, -1, sizeof(s));s[0][0][0][0][0][0] = 1;int n;while(scanf("%d", &n)!=EOF) {memset(arr, 0, sizeof(arr));for(int i=0;i<n;i++)scanf("%d", &arr[i]);printf("%s\n", solve(arr[0],arr[1],arr[2],arr[3],arr[4],arr[5])?"orzwym6912":"orzwang9897");}return 0;
}

View Code

网上查阅了相关的题,理解了这个规则其实同样可以用Nim和来解决,只需要特殊判断全部堆都是1的情况。因为在Nim博弈中,最后一步要取走全部石子,那么本题对于必胜者也可以少取走一颗石子,那么也是必胜。但是如果每堆只有一颗石子,就无法按照Nim博弈的进行最优取法。显然有偶数个为1的堆为必胜态,那么问题就解决了。

#include<iostream>
#include<cstdio>
using namespace std;
int main()
{int n;while(scanf("%d", &n)!=EOF) {int ans = 0, k;bool flag = 1; int cnt = 0;while(n--) {scanf("%d", &k);if(k==0) continue;if(k!=1) flag = 0;else cnt++;ans ^= k;}if(!flag)printf("%s\n", ans==0?"orzwang9897":"orzwym6912");elseprintf("%s\n", cnt&1?"orzwang9897":"orzwym6912");}return 0;
}

View Code

F - 背包弹夹平底锅

通过找规律+oeis.org归纳出公式,最后发现了这题主要是得到第二类斯特林数。结果就是s(n, i)*i!/n^m。

那么怎么求s(n, i)呢?查阅资料得知这个跟组合数有相似的递推性质,可以在O(n2)时间内求出s(n, i)。此题n,m<100000,显然不行。

翻了好多篇博客,都提到要用快速傅里叶变换,然后就自闭了。

(待补。。。)

G - 小鸟的修路计划

这题就是求有n个不同节点的连通图的种类。

开始自己手算了递推式,样例都算不对,只好百度借鉴了别人的公式。

写好快速幂+组合数WA了好多次,debug很久,一度怀疑幂运算取模出错了,要用那啥费马小定理。最后比对别人的输出才突然注意到三个ll相乘会溢出的重大bug。。。

先预处理,T次查询直接输出结果,时间复杂度O(m2+T)。

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;const ll mod=1000000007;
ll C[1010][1010], f[1010];
ll pow_mod(ll a, ll x)
{ll res = 1;while(x) {if(x&1) res = (res*a)%mod;a = (a*a)%mod;x >>= 1;}return res;
}
ll Cn2(int n)
{return (ll)n*(n-1)/2;
}
void solve()
{for(int i=0;i<1010;i++)C[i][i] = C[i][0] = 1;for(int i=1;i<1010;i++)for(int j=1;j<=i;j++) {C[i][j] = (C[i-1][j] + C[i-1][j-1])%mod;}f[1] = f[2] = 1;
//    f[3] = 4;for(int n=3;n<1010;n++) {for(int i=1;i<n;i++)f[n] = (f[n] + ((C[n-1][i-1]*f[i])%mod * pow_mod(2, Cn2(n-i))%mod))%mod;f[n] = ((pow_mod(2, Cn2(n))-f[n])%mod+mod)%mod;}
}int main()
{int T; cin>>T;solve();while(T--) {int m; scanf("%d", &m);printf("%lld\n", f[m]);}return 0;
}

View Code

// 2的C(n,2)次方我为什么要用组合数。。。

H - 超长递增序列

一个简单技巧题被我硬生生用二分法暴力求解,一直TLE到怀疑人生。(虽说复杂度O(T*2n*logn)很勉强的样子)

由于a1 + a2 + ... + ai <= a(i+1),那么对于K,我们从后往前查找,如果a(i+1)<=K,不取a(i+1)的话就无法选择前i项使总和为K,所以a(i+1)必选。因此不断往前贪心即可。

时间复杂度O(T*n)

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long ll;
ll arr[44], K;ll pow2(ll a, int x)
{ll res = 1;while(x) {if(x&1) res *= a;a *= a;x >>= 1;}return res;
}int main()
{int T, n; scanf("%d", &T);while(T--) {scanf("%d %lld", &n, &K);for(int i=1;i<=n;i++)scanf("%lld", &arr[i]);int i=n;ll res = 0;while(K>0) {while(i>=1 && arr[i]>K) i--;if(i<1) break;elseK -= arr[i], res += pow2(2, i);}if(K==0)printf("%lld\n", res);elseprintf("-1\n");}return 0;
}

View Code

I - 两数和

题意:给了n个数两两之间C(n,2)组和,求出原数列,如有多组,输出字典序最小的解。

假设有a1<=a2<=a3<=... <=an,可以得到最小和一定是a1+a2,次小和一定是a1+a3。(仔细想想是不是)

那么如果我们假设第三小的和是a2+a3的话,前三个数就确定了。显然接下来最小的和就是a1+a4,求出a4,删去a2+a4,a3+a4,那么最小的就是a1+a5,依次类推,a5,a6,... ,都能计算出来。

但问题没这么简单。

我们其实无法确定a1+a4,a1+a5,..., a1+an与a2+a3的大小顺序。可以肯定的是,a2+a3的值一定在这n-3+1=n-2组最小值之中。

所以采用穷举并检验后续能否全部算出,时间复杂度O(T*n3),可行。

PS. 注意n=2的特殊处理。

// 考虑到每次检验失败都要重新传入n*(n-1)/2组值,感觉会拖慢时间,自作聪明将multiset<ll>传引用,结果WA了半天还不知道哪出错了。。。

// 对于要在函数内进行修改且不需要返回更新值的变量,还是不要想当然传引用了。。。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<set>
#include<vector>
using namespace std;
typedef long long ll;
typedef multiset<ll>::iterator msPt;
int n;
ll ai, a[120];
bool solve(ll c1, ll c2, ll c3, multiset<ll> S)
{if((c1+c2+c3)%2)return 0;if(c1+c3<=c2||c1+c2<=c3)return 0;a[1] = (c1+c2-c3)/2;a[2] = (c1+c3-c2)/2;a[3] = (c2+c3-c1)/2;for(int i=4;i<=n;i++) {a[i] = *S.begin()-a[1]; S.erase(S.begin());for(int j=2;j<i;j++) {if(S.find(a[j]+a[i])==S.end())return 0;elseS.erase(S.find(a[j]+a[i]));}}for(int i=1;i<=n;i++)printf("%lld%c", a[i], n==i?'\n':' ');return 1;
}int main()
{int T; cin>>T;while(T--) {scanf("%d", &n);if(n==2) {scanf("%lld", &ai);if(ai>1)printf("1 %lld\n", ai-1);elseprintf("Impossible\n");continue;}multiset<ll> S;for(int i=0;i<n*(n-1)/2;i++) {scanf("%lld", &ai);S.insert(ai);}ll c1 = *S.begin(); S.erase(S.begin());ll c2 = *S.begin(); S.erase(S.begin());//    ll c3 = *S.begin(); S.erase(S.begin());
vector<ll> C3;for(msPt it = S.begin(); C3.size()<n-2&& it!=S.end();it++)if(C3.size() && *it==C3[C3.size()-1]) continue;elseC3.push_back(*it);bool flag = 0;for(int i=0;i<C3.size();i++) {S.erase(S.find(C3[i]));if(!solve(c1, c2, C3[i], S)) {S.insert(C3[i]);} else {flag = 1;}}if(!flag)printf("Impossible\n");}return 0;
}

View Code

J - 垒箱子

哈哈不会,据说需要各种暴力+建图。我还是好好掌握prim啊、dijkstra啊这种再来吧。。。

K - 签到

到了传说中的签到题,好几天都一直没人做。读完题发现就是求解三个球面的交点问题,可以直接联立方程求解。

为了体现出它不是一个数学问题,我尝试用计算几何的思维,二分两平面的交线。WA了十来次才发现连输出要求都没注意。改过后仍然WA。。。

最后还是用数学方法解方程通过的。赛后题解提供了五六种思路,我尝试了两种二分都失败了,改日再研究计算几何。。。

View Code

转载于:https://www.cnblogs.com/izcat/p/10769421.html

2019 西电ACM校赛网络赛 题解相关推荐

  1. 2019 杭电多校第六场 题解

    比赛记录 注意随机数据 ,1-n排列这种,一般都有啥暴力重构之类的方法,期望重构次数很少之类的 1005也是这样,因为n^2但只有n个值有数,所以就可以n^2logn 题解 1001 Salty Fi ...

  2. 2019 ACM - ICPC 上海网络赛 E. Counting Sequences II (指数型生成函数)

    繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量题解和代码,题目难度不一定按照题号排序,我会在每道题后面加上题目难度指数(1∼51 \sim 51∼5),以模板题难度 11 ...

  3. 【2019杭电多校训练赛】HDU6681 / 1002-Rikka with Cake 题解(扫描线)

    [2019杭电多校训练赛]HDU6681 / 1002-Rikka with Cake 题解 题意 思路 代码 题目来自于:HDU6681 Rikka with Cake 题意 题目的大意是给定你一个 ...

  4. 2019年安徽大学ACM/ICPC实验室新生赛题解

    本文仅作个人收藏学习使用 题目及解析来源牛客竞赛网 //作者:王清楚 //链接:https://ac.nowcoder.com/discuss/351408?type=101&order=0& ...

  5. 2019杭电多校 第七场 Kejin Player 6656(求期望值)

    2019杭电多校 第七场 Kejin Player 6656(求期望值) 题目 http://acm.hdu.edu.cn/showproblem.php?pid=6656 题意 给你n,q.表示有n ...

  6. 高职网络系统管理国赛--网络赛题1路由选路解析

    高职网络系统管理国赛–网络赛题1路由选路解析 题目要求如下: (1)龙首原支行的原生产网段(VLAN 410).办公网段(VLAN 460)需要与省行的业务区.生产办公区的业务互联互通,需要在交换机S ...

  7. 2022年华为ICT实践赛网络赛道题库全(1107道题目)

    2022年华为ICT实践赛网络赛道题库 今年的省赛初赛17号比,好多省份因为疫情原因线上,真的羡慕各位学弟学妹,想当初自己和队友在实验室里通宵刷题和看教学视频(不过最后结果是好的自己拿了省一国二),线 ...

  8. 2019杭电多校第9场1002 Rikka with Cake HDU6681

    2019杭电多校第9场1002 Rikka with Cake HDU6681 题意:给你若干个点按上下左右切割平面,最后问平面内有几块被切割开来. 解法1:红黑树+思维+贪心 A:根据欧拉定理可以得 ...

  9. 2022杭电多校第八场题解

    2022杭电多校第八场 Theramore(思维) 题意 给定一个01字符串,每次可以将一个奇数长度的区间翻转,求操作后字典序最小的字符串. 分析 翻转奇数长度的区间,元素位置的奇偶性不变,统计奇数位 ...

最新文章

  1. python清华大学出版社第三章课堂作业的答案_Python程序设计清华大学出版社董付国第3章选择与循环题库.ppt...
  2. 精通python爬虫框架-精通Python爬虫框架Scrapy
  3. 数组静态初始化【应用】
  4. Spring注解编程基石(二)
  5. 谷歌全新OS曝光:它是操作系统世界里一种全新的艺术
  6. php加skplayer,WordPress整合ckplayer(最新)
  7. java dvr_java – 如何设置与DVR的连接并解码数据?
  8. 【解决】nacos Ignore the empty nacos configuration and get it based on dataId
  9. 东芝计算机配置,东芝z830配置 东芝Z830-K02S参数【图文】
  10. 如何将音视频中的伴奏背景音乐和人声分离?
  11. 移动端框架 - Bootstrap
  12. HTTP 204,304状态码
  13. 电视盒子 android tv6,电视盒子到底是什么?智能电视/盒子究竟究竟该选谁?
  14. springmvcHandlerMapping解析
  15. linux中.bashrc 等文件中的rc是什么意思
  16. oec数据挖掘用到的hbase
  17. 递归求阶乘和--PTA
  18. 电脑死机的常用排查思路
  19. 【技术认证题库】SCCA理论AD考试【初级】
  20. 如何下载阳泉市卫星地图高清版大图

热门文章

  1. SpringBoot中关闭Mybatis以及RocketMQ日志打印
  2. r7 5800u和 r5 4500u的差别大吗
  3. nuwa :线程分析,nuwa 如何产生,nuwa如何恢复线程?
  4. IDEA 提交项目至Git与获取Git项目
  5. 领导想提拔你,会暗送这3个“秋波”,你要做足前戏,把握节奏
  6. 历次周赛、专场竞赛、春秋赛题目场次及对应具体题目题号+链接汇总
  7. 微信公众号的主页链接是怎么调出来的?
  8. 斯特林公式(Stirling)
  9. STM32F407ZG TIM通用定时器
  10. 【华为云原生入门级认证】第 2 章 云原生基础设施之容器技术