第一周任务 - Virtual Judge (vjudge.net)
http://t.csdn.cn/rcwO7
第一周任务 - Virtual Judge (vjudge.net)
【题目描述】
然后所有玩家成对玩,每对玩家只玩一次。因此,例如,如果总共有四个玩家,则进行六场比赛:第一场比赛对第二场比赛,第一场比赛对第三场比赛,第一场比赛对第四场比赛,第二场比赛对第三场比赛,第二场比赛对第四场比赛,第三场比赛对第四场比赛。
这些游戏中的每一个都以某种方式决定了获胜者,但规则相当复杂,所以我们不会在这里描述它们。重要的是向获胜者支付了多少筹码。让第一个玩家的牌有数字a1,a2,…,am,还有第二个玩家的卡b1,b2,...,bm.然后游戏的获胜者得到∣a1-b1∣+∣a2-b2∣+⋯+∣am-bm∣总锅中的薯条,其中∣x∣表示绝对值x.
要确定总底池的大小,有必要计算获胜者在所有游戏中的总奖金。
【输入】
每个测试由多个测试用例组成。第一行包含一个整数t (1≤t≤1000) — 测试用例的数量。测试用例的说明如下。
每个测试用例的第一行包含两个整数n和m (1≤n⋅m≤3⋅10 5) — 一副牌中的牌数和一张牌上的数字计数。
以下每一项n测试用例集的行包含m整数(c<=10 6)
保证总计n⋅m在所有测试中不超过3⋅10 5.
【输出】
打印一个数字 — 所有游戏的奖金总额。
解题思路:
题目要求每行数据对应的牌之间的差,然后累加每一种行与行对应的情况。
这个题目要求计算每个玩家之间对应的牌之间的差距(绝对值),肯定不能直接将每一行的数据进行排序,因为当打乱牌的顺序时,牌与牌之间的差可能会发生变化。
有个要注意的点是:通常存放如图的数据时,用一个二维数据就可以了,但是这里给出的限定是:n⋅m≤3⋅10 5,不知道n和m的准确范围,而定义一个a[3⋅10 5][3⋅10 5]又会数组超出范围。
所以这里用到对象数组(容器),它可以用来存放任意类型的动态数组,这里的话可以将n和m的值输入后,再定义一个规定范围的vector容器,可以解决题目中的这个问题。
vector<vector<int>> a(m,vector<int>(n));
还有个要注意的点:仔细看数据的范围会发现:计算出来的结果肯定会出现超出int范围的值,要注意使用long long存储数据 。
接下来还是不好解决这个问题,因为要保证时间不超限的情况下,还有考虑数字的正负。并且先前所说的将每个玩家手中的牌按序排列会改变最终的结果。所以换一种思考方式,题目给的样例是n*m,但是我可以将它转换为m*n的形式:
第一个样例,对于第二张图,它是在输入的时候将行列转换,此时在三列之间进行计算,对于每一行的三列排序后,然后进行计算。
用两层循环,第一层循环将行排序,第二层循环用计数器计算总数。
例如第一行,排序后是1,3,7,对于第一个的1来说,它被后面的n-j-1个数都减一遍(j是排序后的位置),对于第二个的3,它被后面的n-j-1个数减一遍,并且用它减去前面的 j 个数。
代码如下:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main() {
int t;
int n, m;
cin >> t;
while (t--) {
long long sum = 0;
cin >> n >> m;
//根据输入的n,m的大小分配开辟的空间,这里的m是参与的人数,n是每个人的牌数
vector<vector<long long>> a(m, vector<long long>(n));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> a[j][i];
}
}
long long s=0;
//每个人的牌不能变换位置,但是每个人的位置变了,无影响
for (int i = 0; i < m; i++) {
sort(a[i].begin(), a[i].end());
for (int j = 0; j <n; j++) {
//代表当前点将会被加多少次(j),和减多少次(n-j-1)
s = s + a[i][j] * j - a[i][j] * (n-j - 1);
}
}
cout << s << endl;
}
}