2021-BNUZ-IT节程序设计竞赛网络赛题解
文章目录
- 前言
- 我的徒弟都是实习生
- 快穿之我只想测身高
- 凡人追妹传之大学篇
- 北宋大烟篓
- 游戏败家子
- 超神排位赛
- 这个大师太过正经
- 糖果的四十六亿种分法
- 我有一座研究院
- 特拉福珠宝俱乐部
- 吃糖直播间
- 我师傅实在太稳健了
- 大奉卖笔人
前言
网络赛有效提交者143人(不包括打星选手),题目类型包括数据结构,模拟,动态规划,贪心等算法
让我们来看看排行前十的选手(没错,打星选手就是大佬,学长闲着做了一下直接AK了…)
本次IT节网络赛由某点倾情赞助…就怪
去年是二次元,今年是网文系列
题目名字改编自以下小说
我的徒弟都是大反派
快穿之xxx系列(这个太多了)
凡人修仙传之仙界篇
北宋大丈夫
明朝败家子
超神机械师
这个人仙太过正经
进化的四十六亿重奏
我有一座冒险屋
手术直播间
特拉福买家俱乐部
我师兄实在太稳健了
大奉打更人
听说有人觉得插图好看,那就找出题人要照片吧,其实有些图片和题目都没啥关系~
下面给出C++代码
没有学习C++的同学,可以简单把cin
看成C语言里的scanf
,把cout
看成C语言里的printf
我们会根据一定比例挑选进入现场赛的选手,届时将会将名单公布,欢迎关注公众号北师珠ACMICPC
,敬请期待
我的徒弟都是实习生
简单组合数学问题
有一点点小坑,如果按照正常算的话会溢出(边界数据阶乘unsigned long long都存不下)
坑就在这里,我们需要的是解决溢出问题,不是时间
看着很少有一发过的人,基本都被出题人坑了一手
#include<iostream>using namespace std;
typedef long long ll;
ll cb[100001];//ll C(ll k,ll n){//溢出的做法
// ll a = n-k,b = k;
// if(a>b){//保证a最小
// a^=b^=a^=b;
// }
// if(a==0)return 1;
// ll res = 1;
// for(int i=n ; i>b ; i--){// res*=i;
// }
// for(int i=2 ; i<=a ; i++){// res/=i;
// }
// return res;
//}ll C(ll k, ll n) {//优化ll a = n - k, b = k;if (a > b) {//保证a最小a ^= b ^= a ^= b;}if (a == 0)return 1;ll res = 1;for (int i = n, j = 1; i > b; i--, j++) {res *= i;if (j <= a) {res /= j;}}return res;
}int main() {ll t, n, m;while (cin >> t >> m >> n) {ll res = 0;for (int i = 4; i <= t - 1; i++) {int man = i;int girl = t - i;if (man <= n && girl <= m) {res += C(man, n) * C(girl, m);}}cout << res << "\n";}
}
快穿之我只想测身高
思考:
题目中的M对关系实际上是人之间身高的相对大小关系。具体来说,我们建立一个数组C,数组中起初全为0。若一条关系指明Ai和Bi可以互相看见(不妨设Ai<Bi),则把数组C中下标为Ai+1到Bi-1的数都减去1,意思是在Ai和Bi中间的人,身高至少要比它们小1。因为第P个人是最高的,所以最终C[p]一定为0。其他的人与第P个人的身高差距就体现在数组C中。换言之,最后第i个人的身高就等于H+C[i]。如果我们朴素执行把数组C中下标为Ai+1到Bi-1的数都减去1的操作,那么整个算法的时间复杂度为O(NM),复杂度过高。一个简单而高效的做法是,额外建立一个数组D,对于每对A和B,令D[Ai+1]减去1,D[Bi]加上1。其含义是:“身高减小1”的影响从Ai+1开始,持续到Bi-1,在Bi结束。最后,C就等于D的前缀和。
上述优化后的算法把对一个区间的操作转化为左、右两个端点上的操作,再通过前缀和得到原问题的解。这种思想很常用,我们在后面还会多次遇到。该算法的时间复杂度为O(N+M)。
另外,在本题的数据中,一条关系(A,B)可能会输入多次,要注意检查,对于重复的关系,只在第一次出现时执行相关操作即可。这一点需注意
#include<bits/stdc++.h>using namespace std;
map<pair<int, int>, bool> existed;
int c[10010], d[10010];int main() {int n, p, h, m;cin >> n >> p >> h >> m;for (int i = 1; i <= m; i++) {int a, b;scanf("%d%d", &a, &b);if (a > b) swap(a, b);if (existed[make_pair(a, b)]) continue;d[a + 1]--;d[b]++;existed[make_pair(a, b)] = true;}for (int i = 1; i <= n; i++) {c[i] = c[i - 1] + d[i];printf("%d\n", h + c[i]);}cout << endl;
}
凡人追妹传之大学篇
可以插入到中间,左边和右边,也有可能无法插入
分别进行判断即可
我就想着不算难吧,但是就只有几个人写了
#include<bits/stdc++.h>using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
int cb[100000];
int cc[100000][2];int main() {int n;while (cin >> n) {for (int i = 0; i < n; i++) {cin >> cb[i];}sort(cb, cb + n);if (n == 1) {cout << "-1\n";} else if (n == 2) {//左边 右边 中间 int c = cb[1] - cb[0];if (c & 1) {cout << "2\n";cout << cb[0] - c << " " << cb[1] + c << "\n";} else if (cb[0] == cb[1]) {cout << "1\n";cout << cb[0] << "\n";} else {cout << "3\n";cout << cb[0] - c << " " << cb[0] + c / 2 << " " << cb[1] + c << "\n";}} else if (n >= 3) {//两个中间,左边右边,没有 //判断所有只有一个不等--中间int pd = 0;int min = INF;for (int i = 1; i < n; i++) {//找最小的 if (cb[i] - cb[i - 1] < min) {min = cb[i] - cb[i - 1];}}for (int i = 1; i < n; i++) {if ((cb[i] - cb[i - 1]) != min && (cb[i] - cb[i - 1]) == min * 2) {//可以插入 cc[pd][0] = cb[i];cc[pd++][1] = cb[i - 1];} else if ((cb[i] - cb[i - 1]) != min) {pd = -1;//直接失败 break;}}//全部相同int q = 1;for (int i = 1; i < n; i++) {if (cb[i] != cb[i - 1]) {q = 0;}}if (q) {cout << "1\n";cout << cb[0] << "\n";} else {if (pd > 1 || pd == -1) {//>=一个不等--没有 cout << "0\n";} else if (pd == 1) {cout << "1\n";cout << (cc[0][0] + cc[0][1]) / 2 << "\n";} else if (pd == 0) {//所有都等,左右 int c = cb[1] - cb[0];cout << "2\n";cout << cb[0] - c << " " << cb[n - 1] + c << "\n";}}}}
}
北宋大烟篓
经典约瑟夫环问题
如果看不懂代码的可以看这里
https://blog.csdn.net/u011500062/article/details/72855826
#include <iostream>
#include <algorithm>using namespace std;int cir(int n, int m) {int p = 0;for (int i = 2; i <= n; i++) {p = (p + m) % i;}return p + 1;
}int main() {int t;int n, m;cin >> t;for (int i = 0; i < t; i++) {cin >> n >> m;cout << cir(n, m) << "\n";}
}
游戏败家子
动态规划
假设数组 cost 的长度为 n,则 n个阶梯分别对应下标 0 到 n-1,楼层顶部对应下标 n,问题等价于计算达到下标 n 的最小花费。可以通过动态规划求解。
创建长度为 n+1 的数组dp,其中dp[i] 表示达到下标 i的最小花费。
由于可以选择下标 0或 1 作为初始阶梯,因此有 dp[0]=dp[1]=0。
当 2≤i≤n 时,可以从下标 i−1 使用 cost[i−1] 的花费达到下标 i,或者从下标 i-2使用 cost[i−2] 的花费达到下标 i。为了使总花费最小,dp[i] 应取上述两项的最小值,因此状态转移方程如下:
dp[i]=min(dp[i−1]+cost[i−1],dp[i−2]+cost[i−2])
依次计算 dp 中的每一项的值,最终得到的dp[n]即为达到楼层顶部的最小花费。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<algorithm>int minCostClimbingStairs(int *cost, int costSize) {int dp[costSize];dp[0] = cost[0];dp[1] = cost[1];for (int i = 2; i < costSize; i++) {dp[i] = fmin(dp[i - 1], dp[i - 2]) + cost[i];}return fmin(dp[costSize - 1], dp[costSize - 2]);
}int main() {int cost[1000];int costSize = 0;int n;while (~scanf("%d", &n)) {while (n--) {scanf("%d", &costSize);for (int i = 0; i < costSize; i++) {scanf("%d", &cost[i]);}printf("%d", minCostClimbingStairs(cost, costSize));}}}
超神排位赛
模拟题,灵感来自某年山东省省赛,有一道炉石的排位机制模拟
按照题意模拟即可,只是细节要注意,例如升段的时候,降段位的时候,王者50星,王者不会掉到星耀等几种情况
#include<bits/stdc++.h>using namespace std;char r[10][20] = {"", "Bronze", "Silver", "Gold", "Platinum", "Diamond", "Starry", "Master", "Challenger"};
int limit[] = {0, 3, 3, 4, 5, 5, 5, 999, 999};//星数限制
int limit2[] = {0, 3, 4, 4, 5, 5, 5, 999, 999};//分段数量限制
int rule[] = {0, 3, 3, 3, 4, 5, 6, 999, 999};//连胜规则数量
char br[6][10] = {"", "one", "two", "three", "four", "five"};
//cnt 段位下标 counter 小段位下标
int cnt, counter;
char c1[20], c2[20];
int c, n;void ascertain() {//cnt 段位下标 counter 小段位下标 for (int i = 0; i < 9; i++) {if (strcmp(c1, r[i]) == 0) {//相同cnt = i;break;}}for (int i = 0; i < 6; i++) {if (strcmp(c2, br[i]) == 0) {counter = i;break;}}
}void verify() {//王者判定 if (c > limit[cnt] && cnt != 7) {c -= limit[cnt];counter--;if (counter == 0) {cnt++;counter = limit2[cnt];}}
}int main() {int cb[1000];while (cin >> c1 >> c2 >> c) {ascertain();//使cnt,counter,c转化为数字cin >> n;int plus = 0;for (int i = 0; i < n; i++) {cin >> cb[i];//判断连胜的过程//判断加星升段的过程 if (cb[i] == 1) {//连胜场数 plus++;} else {plus = 0;}if (plus == rule[cnt] && cb[i] == 1) {//可以连胜 c += 2;verify();plus = 0;} else if (cb[i] == 1) {//普通胜利 c++;verify();} else if (cb[i] == -1) {//本身段位是0的可能,退小段位,大段位 if (cnt == 1 && counter == 3 && c == 0 || cnt == 7 && c == 0) {continue;//青铜,王者的特殊情况 }c--;if (c == -1) {//掉小段位counter++;if (counter == limit2[cnt] + 1) {//掉大段位counter = 1;cnt--;}c = limit[cnt] - 1;}}}if (cnt == 7 && c < 50) {//王者 cout << r[cnt] << " " << c << "\n";} else if (cnt == 7 && c >= 50) {//荣耀王者 cout << r[8] << "\n";} else {cout << r[cnt] << " " << br[counter] << " " << c << "\n";}}
}
这个大师太过正经
简单快速幂
按照一般的暴力过不了
#include<stdio.h>typedef long long ll;int main() {ll t;scanf("%lld", &t);while (t--) {ll n, a, b, p = 1000003;ll res = 0;scanf("%lld", &n);for (ll i = 0; i < n; i++) {ll q = 1;scanf("%lld %lld", &a, &b);while (b) {if (b & 1)q = q * a % p;b >>= 1;a = a * a % p;}res = (res + q) % p;}printf("%lld\n", res % p);}return 0;
}
糖果的四十六亿种分法
题意:有n个盒子组成一个圆,盒子里总共有不超过n个蛋糕,有的有好几个,有的为0。可以将一个盒子里的蛋糕往左右两个盒子里移动,一次只能移动一个,使最终每个盒子里有不超过一个蛋糕(可以没有),求最小的移动数
思路:把盒子分为两种,有蛋糕和没蛋糕的,然后建图,对于有蛋糕的盒子拆点,拆为蛋糕数-1个点,因为它本身留一个蛋糕不移动。需要注意的是因为是个圆,所以移动的路径肯定不会大于n/2,大于n/2时判断一下就好了。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>using namespace std;const int N = 510;
const int INF = 0x3f3f3f3f;
int n, nx, ny;
int lx[N], ly[N], slack[N], match[N], s[N][N];
bool visx[N], visy[N];
int v[N], tmp[N];bool hungary(int v) {visx[v] = true;for (int i = 0; i < ny; i++) {if (visy[i]) continue;if (lx[v] + ly[i] == s[v][i]) {visy[i] = true;if (match[i] == -1 || hungary(match[i])) {match[i] = v;return true;}} else slack[i] = min(slack[i], lx[v] + ly[i] - s[v][i]);}return false;
}void km() {memset(match, -1, sizeof match);memset(ly, 0, sizeof ly);for (int i = 0; i < nx; i++)lx[i] = -INF;for (int i = 0; i < nx; i++)for (int j = 0; j < ny; j++)lx[i] = max(lx[i], s[i][j]);for (int i = 0; i < nx; i++) {memset(slack, 0x3f, sizeof slack);while (true) {memset(visx, 0, sizeof visx);memset(visy, 0, sizeof visy);if (hungary(i)) break;else {int d = INF;for (int j = 0; j < ny; j++)if (!visy[j]) d = min(d, slack[j]);for (int j = 0; j < nx; j++)if (visx[j]) lx[j] -= d;for (int j = 0; j < ny; j++)if (visy[j]) ly[j] += d;else slack[j] -= d;}}}
}int main() {int n;int a;cin >> a;while (a--) {cin >> n;int t = n / 2;for (int i = 0; i < n; i++)scanf("%d", v + i);for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)s[i][j] = -INF;int cnt1 = 0, cnt2 = 0;for (int i = 0; i < n; i++)if (v[i] == 0)tmp[i] = cnt2++;for (int i = 0; i < n; i++)for (int j = 0; j < v[i] - 1; j++) {for (int k = 0; k < n; k++) {if (v[k] == 0) {if (abs(k - i) >= t)s[cnt1][tmp[k]] = -(n - abs(k - i));elses[cnt1][tmp[k]] = -abs(k - i);}}cnt1++;}nx = cnt1, ny = cnt2;km();int res = 0;for (int i = 0; i < ny; i++)if (match[i] != -1)res += s[match[i]][i];printf("%d\n", -res);}return 0;
}
我有一座研究院
过题人数最多的一道题
三种方法:暴力,贪心,公式
暴力
如果哪边的轻就加哪边,直到一边数量已经到达一半
#include<iostream>
#include<cmath>using namespace std;int main() {int t;cin >> t;while (t--) {int a = 0, b = 0, n, ta = 0, tb = 0;cin >> n;for (int i = n; i > 0; i--) {if (ta == n / 2) {b += pow(2, i);tb++;} else if (tb == n / 2) {a += pow(2, i);ta++;} else if (a <= b) {a += pow(2, i);ta++;} else if (a > b) {b += pow(2, i);tb++;}}cout << abs(a - b) << "\n";}return 0;
}
贪心
最后一个和前n-1个是一组,其他是一组,因为要保持两边的绝对值最小
#include<cmath>
#include<iostream>using namespace std;int main() {int t;cin >> t;while (t--) {int a = 0, b = 0, n;cin >> n;a += pow(2, n);for (int i = 1; i < n / 2; i++) {a += pow(2, i);}for (int i = n / 2; i < n; i++) {b += pow(2, i);}cout << abs(a - b) << "\n";}return 0;
}
公式
我们可以得出规律,按照规律推导结果
#include<iostream>
#include<cmath>using namespace std;int main() {int t, n;cin >> t;while (t--) {cin >> n;cout << pow(2, n / 2 + 1) - 2 << "\n";}return 0;
}
特拉福珠宝俱乐部
题意:
求树上每个点能走出的最远距离
思路:
树形DP
程序中的数据结构:
A数组记录V结点沿子树方向最长路所经过V的孩子编号。
B数组记录沿子树方向的次长路长度。
dp1数组 记录子树方向的最长路。
dp2数组记录来自父节点的最长路。
vectorcnt:记录每条边的信息。
我们假设一个结点V的孩子为{v1,v2,v3……vn};
如果vi在V沿子树方向的最长路上
那么dis【vi】 = max(dp1【vi】,max(dp2【V】,B【V】) + dis(V,vi))
说一下内嵌的max,以图中2(V)结点2结点来自父节点的最长路和2结点的子树方向次长路的较大值加上V 和vi的距离如果vi不在V沿子树方向的最长路上
那么dis【vi】= max(dp1【V】,dp2【V】) + dis(V, vi);
最长路要么来自父节点子树方向的最长路加上dis(V,vi),要不来自父节点V的从V的父节点来的最长路 + dis(V, vi);
对于根节点特殊处理因为没有父节点只有次最长路,并且单孩子的结点没有次长路。
#include<iostream>
#include<sstream>
#include<algorithm>
#include<cstdio>
#include<string.h>
#include<cctype>
#include<string>
#include<cmath>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
using namespace std;
const int INF = 510;
int n, A[INF], B[INF], dp1[INF],dp2[INF];
typedef pair<int, int> PLL;
vector<PLL>cnt[INF];int dfs1(int root){int len = cnt[root].size();if(!len){//搜索到叶子return 0;}int Max = -1, loc1 = -1, loc2 = -1;for(int i = 0; i < len; i++){//寻找最长路if(dfs1(cnt[root][i].first) + cnt[root][i].second > Max){Max = dfs1(cnt[root][i].first) + cnt[root][i].second;loc1 = i;}}dp1[root] = Max;Max = -1;A[root] = loc1;for(int i = 0; i < len; i++){//寻找次长路if(dp1[cnt[root][i].first] + cnt[root][i].second > Max && i != loc1){Max = dp1[cnt[root][i].first] +cnt[root][i].second;loc2 = i;}if(loc2 != -1)B[root] = Max;}return dp1[root];
}void dfs2(int root){int len = cnt[root].size();for(int i = 0; i < len; i++){if(i == A[root]){//这个孩子在沿子树方向的最长路径上dp2[cnt[root][i].first] = max(dp2[root], B[root]) + cnt[root][i].second;}else{dp2[cnt[root][i].first] = max(dp2[root], dp1[root]) + cnt[root][i].second;}dfs2(cnt[root][i].first);}
}
int main(){while(scanf("%d",&n) != EOF){memset(dp1, 0, sizeof(dp1));memset(B, 0, sizeof(B));memset(A, 0, sizeof(A));memset(dp2, 0, sizeof(dp2));for(int i = 1; i <= INF; i++){cnt[i].clear();}for(int i = 2; i <= n; i++){int x1, x2;scanf("%d%d", &x1, &x2);cnt[x1].push_back(make_pair(i, x2));}dfs1(1);dfs2(1);for(int i = 1; i <= n; i++){cout<<max(dp1[i], dp2[i])<<endl;}}return 0;
}
吃糖直播间
首先考虑最简单的情况。如果只有一个箱子,则选择该箱子,可以选择到最高总糖果数。如果只有两个箱子,则由于两个箱子相邻,不能同时选择,只能选择其中的一个箱子,因此选择其中糖果数较高的箱子进行选择,可以选择到最高总糖果数。
如果箱子数量大于两个,应该如何计算能够选择到的最高总糖果数呢?对于第 k(k>2) 个箱子,有两个选项:
1.选择第 k 个箱子,那么就不能选择第 k-1 个箱子,选择总糖果数为前 k-2 个箱子的最高总糖果数与第 k 个箱子的糖果数之和。
2.不选择第 k 个箱子,选择总糖果数为前 k-1 个箱子的最高总糖果数。
在两个选项中选择选择总糖果数较大的选项,该选项对应的选择总糖果数即为前 k 个箱子能选择到的最高总糖果数。
用 dp[i] 表示前 i 个箱子能选择到的最高总糖果数,那么就有如下的状态转移方程:
dp[i]=max(dp[i−2]+nums[i],dp[i−1])
边界条件为:
{
dp[0]=nums[0] 只有一个箱子,则吃该箱子中的糖果
dp[1]=max(nums[0],nums[1]) 有两个箱子,选择其中糖果数多的箱子。
}
最终的答案即为dp[n−1],其中 n 是数组的长度。
#include<stdio.h>
#include<iostream>using namespace std;
const int maxn = 110;int arr[maxn], dp[maxn][5];int main() {int t, cas = 0;cin >> t;while (t--) {int n;cin >> n;for (int i = 1; i <= n; i++) {cin >> arr[i];}dp[1][0] = 0;dp[1][1] = arr[1];for (int i = 2; i <= n; i++) {dp[i][0] = max(dp[i - 1][0], dp[i - 1][1]);dp[i][1] = dp[i - 1][0] + arr[i];}printf("Case #%d:\n", ++cas);cout << max(dp[n][0], dp[n][1]) << endl;}
}
我师傅实在太稳健了
我觉得这个看了代码秒懂,这个也是签到题吧…
#include<iostream>using namespace std;int main() {int t;cin >> t;while (t--) {int a, b, c, d, e;cin >> a >> b >> c >> d >> e;if (a - b - c - d - e > 1 ||b - a - c - d - e > 1 ||c - d - e - a - b > 1 ||d - e - a - b - c > 1 ||e - a - b - c - d > 1) {cout << "no\n";} else {cout << "yes\n";}}return 0;
}
你看,是不是秒懂…
大奉卖笔人
大致思路如下:
1、先对输入的数组进行快速排序,从小到大排列
2、先进行第一步优化,将可以去掉的球先去掉,使后面的连续几类球都保持一样的数量,
在此过程中去掉的球的总价格计算进total里面,
这一步优化目的在于找到一个阈值threshold,使得去掉的球的数量threshold <= orders
一旦threshold > orders,结束此步。
这一步结束后,color_count表示优化了多少个类的球的数量,base表示下一步优化时球的基准,
optimize表示没有超过orders的最大threshold,即这一步去掉的球的总数。
例如:[2 4 6 8 10] orders = 20
-> [2 4 6 8 8] threshold = 10-(8×1) = 2 < orders
-> [2 4 6 6 6] threshold = (10+8)-(6×2) = 6 < orders
-> [2 4 4 4 4] threshold = (10+8+6)-(4×3) = 12 < orders
-> [2 2 2 2 2] threshold = (10+8+6+4)-(2×4) = 20 = orders
所以从[2 4 6 8 10]优化后是[2 2 2 2 2]
color_count = 4, base = 2,threshold = 20,optimize = 20
[2 4 6 8 10] orders = 23
-> [2 2 2 2 2] threshold = (10+8+6+4)-(2×4) = 20 < orders
-> [0 0 0 0 0] threshold = 10+8+6+4+2 = 30 > orders
所以从[2 4 6 8 10]优化后是[2 2 2 2 2]
color_count = 4, base = 2,threshold = 30,optimize = 20
3、这一步结束之后,我们已经去掉的球的数量是optimize,剩下的球的数量是orders-optimize
如果orders = optimize,直接返回total,就是最终的价格
否则再进行进一步优化
在第2步中的优化是从球最多的开始,每次优化1个,2个…n个球的数量
而在这一步中,现在要一次优化color_count个球的数量
在优化的过程,去掉的球的总价格就是color_count个等差数列的和
先计算(orders-optimize)/(color_count+1),得到等差数列的n
然后计算(order-optimize)%(color_count+1),得到计算完等差数列后剩下几个单独的球需要取出
a1 = base - n + 1
an = base
然后根据a1,an,n计算出等差数列的和,color_count个等差数列的和就是这一次优化的球的总价格
最后还剩下几个球要单独取出,它们的价格是base-n,数量 < color_count + 1
将批量的和单独的球的总价格都加进total里
最后得到total就是结果
注意在计算过程中注意数字溢出的问题
#include<iostream>using namespace std;void quickSort(int arr[], int low, int high, int size);int maxProfit(int *inventory, int inventorySize, int orders);int main() {int num;cin >> num;int size;int inventory[100000];int orders;while (num--) {cin >> size;for (int i = 0; i < size; i++) {cin >> inventory[i];}cin >> orders;cout << maxProfit(inventory, size, orders) << "\n";}
}void quickSort(int arr[], int low, int high, int size) {if (size == 1)return;if (size == 2) {if (arr[0] >= arr[1]) {int temp = arr[0];arr[0] = arr[1];arr[1] = temp;return;} elsereturn;}if (low >= high)return;int first = low;int last = high;int key = arr[first];while (first < last) {while (first < last && arr[last] >= key) {last--;}arr[first] = arr[last];while (first < last && arr[first] < key) {first++;}arr[last] = arr[first];}arr[first] = key;quickSort(arr, low, first - 1, size);quickSort(arr, first + 1, high, size);
}int maxProfit(int *inventory, int inventorySize, int orders) {quickSort(inventory, 0, inventorySize - 1, inventorySize);long int total = 0;if (inventorySize == 1) {long int a1 = inventory[0] - orders + 1;total = ((long int) orders * (a1 + (long int) inventory[0]) / 2) % 1000000007;return total;}int color_count = 0;long int balls_count = 0;long int threshold = 0;int optimize = 0;for (int m = inventorySize - 1; m >= 0; m--) {balls_count += (long int) inventory[m];if (m > 0)threshold = balls_count - (long int) (inventorySize - m) * inventory[m - 1];elsethreshold = balls_count;if (threshold <= (long int) orders) {optimize = threshold;color_count += 1;} elsebreak;}int base = 0;if (color_count == inventorySize)base = 0;elsebase = inventory[inventorySize - color_count - 1];for (int n = 0; n < color_count; n++) {total = (total +(long int) (inventory[inventorySize - n - 1] - base) * (base + 1 + inventory[inventorySize - n - 1]) /2) % 1000000007;}if (optimize == orders)return total;int left = orders - optimize;int times = left / (color_count + 1);int single = left % (color_count + 1);long int times_total = 0;int a1 = base - times + 1;times_total =((long int) times * ((long int) a1 + (long int) base) / 2 * (long int) (color_count + 1)) % 1000000007;;total = (total + times_total) % 1000000007;total = (total + (long int) (a1 - 1) * (long int) single) % 1000000007;return total;
}
最后预祝各位大佬在现场赛都能取得好成绩
2021-BNUZ-IT节程序设计竞赛网络赛题解相关推荐
- 2022-BNUZ-IT节程序设计竞赛网络赛题解
IT节程序设计竞赛-网络赛题目解析 A-纯阳之体 解析 本题是一个双指针问题,当然直接暴力也是可以做的.主要思想就是先求最长连续且不含重复字符的字串的长度.有了长度之后就可以再进行一次搜索,当长度 ...
- 2019 ICPC中国邀请赛(南昌)暨国际丝绸之路程序设计竞赛-网络赛题解
以下所有AC题解程序来自"仙客传奇"团队. AC题数:10/13 ABCDHIJKLM A. PERFECT NUMBER PROBLEM 解题思路:先编写离线程序计算出最小的5个 ...
- “科林明伦杯”哈尔滨理工大学第十届程序设计竞赛(同步赛) 题解
"科林明伦杯"哈尔滨理工大学第十届程序设计竞赛(同步赛) 题解 萌新又来写题解啦 原题链接 B 减成一 题意:存在n个数,每次操作可以任选一个区间使得区间内的所有数字减一.问最少多 ...
- 2018中国大学生程序设计竞赛-网络选拔赛题解
以下所有AC题解程序来自"仙客传奇"团队. A. Buy and Resell AC的C++语言程序: #include<iostream> #include<c ...
- 2012年北京师范大学新生程序设计竞赛网络赛
好吧... bnu的OJ做的相当不错... 然后复习unix无聊了就拿这场做了水题... 两题不会做悲剧...... A. 校队的聚餐 Time Limit: 2000ms Case Time Lim ...
- 北京林业大学“计蒜客”杯程序设计竞赛 网络赛 马踏棋盘的问题
//使用bfs #include<stdio.h> #include<iostream> #include<utility> #include<queue&g ...
- 北航第十二届程序设计竞赛网络预赛题解
本次比赛共有 401 个用户通过至少一道题目,平均通过 3 题,第一位做出全部题目的同学用时 45:26:37 . 如果有对题目的疑问或是见解,欢迎寄刀片给出题人. 预祝大家在决赛中取得好成绩!没有搜 ...
- 湖南中医药大学信息科学与工程学院第四届大学生程序设计竞赛——正式赛题解
目录 问题A:X星人的统计 问题B:X星人的报数 问题C:X星人的迷宫 问题D:X星人的高考 问题E:X星人的匹配 问题F:X星人的成绩 问题G:X星人的变换 问题H:X星人的游戏 问题I:X星人的宝 ...
- 2017年浙江理工大学程序设计竞赛校赛 题解源码(A.水, D. 简单贪心 ,E.数论,I 暴力)...
Problem A: 回文 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 1719 Solved: 528 Description 小王想知道一个字 ...
最新文章
- linux cpp vscode远程调试 的配置
- iOS 在UILabel显示不同的字体和颜色(转)
- 知识管理促进企业组织能力提升
- 后台服务出现明显“变慢”,谈谈你的诊断思路?
- Java GUI界面
- 浅谈对px em rem的理解
- SQL关联查询————LEFT JOIN关键字的使用
- JDK、JRE、javac和JVM的关系
- 信息发布系统 Jquery+MVC架构开发(3) 解决方案创建
- 大数据Hadoop学习(一)入门
- 互联网公司的敏捷开发是怎么回事?这一份软件工程书单送给你!
- WPF 框架开发 加入 InternalsVisibleToAttribute 特性让其他程序集可以访问 internal 权限成员
- IAST 实践利用洞态做开源组件的安全治理
- SPFA算法模板(刘汝佳版)--Wormholes POJ - 3259
- Windbg的获取与安装教程
- Pytorch训练问题:AssertionError: Invalid device id
- 【Linux 内核 内存管理】内存映射相关数据结构 ③ ( vm_area_struct 结构体成员分析 | shared 成员 | anon_vma_chain 成员 | anon_vma 成员 )
- 微信小程序章节自测--6-7-8-9-有解析
- 服务器和PC Server介绍
- 用python或者vba把一个excel表格拆分成多个excel表格