为了更好的阅读体检,可以查看我的算法学习博客第二题-南北对决
https://codefun2000.com/p/P1138
在线评测链接:P1287
题目描述
南派北派武林大会开始了。本次攻擂赛有 n 名武者参加,其中按顺序第 i 名武者获得战斗力属性为 i 。每名武者分来自南派或者北派。如果不同派系的武者在擂台上相遇,战斗力属性值大的获得胜利,如果同派系的武者在擂台上相遇,强者会相让弱者,战斗力属性值小的会获得胜利。参加战斗的所有武者两两都会进行一场决斗,请你计算出每名武者获胜的次数。
输入描述
单个测试用例包含多组数据
输入第一行为一个整数 T ,表示有 T组测试样例。
对于每一组数据,包含两行数据,第一行是人数 n
输入第二行为n 个数 表示派系所属 (
只会取 0 或 1),0 表示来自南派, 1表示来自北派
数字间两两空格隔开
输出描述
对于每组数据,输出一行,包括 n 个整数,每个整数表示每个人能赢多少场。
样例
输入
3 9 0 0 1 0 0 1 0 0 1 6 1 1 0 1 1 0 4 1 0 0 0
输出
5 4 4 4 3 5 3 2 6 3 2 3 2 1 4 0 3 2 1
思路
模拟 + 前缀和
按照题意模拟,从小到大存储每个阵营的数。
对于每个数 x,计算自己阵营中大于 x 的数,以及敌方阵营中小于 x 的数。
可以用一个前缀和维护两个阵营中小于 x 的数的个数。
时间复杂度:O(n)
前缀和学习
这是一个非常"裸"的前缀和题.没有接触过前缀和这个知识点的同学们可以学习:Oi-Wiki-前缀和&差分
类似题目推荐
LeetCode
一维前缀和
-
2559. 统计范围内的元音字符串数
-
560.和为 K 的子数组
-
325.和为 K 的最长子数组长度
二维前缀和
1.304.二维区域和检索 - 矩阵不可变
2.363.最大子矩阵和
Codefun2000
前缀和相关
1.P1140 美团 2023.04.01-第四题-倒水魔法
2.P1117 阿里巴巴 2023.03.26-第一题-切割环形数组
3.P1050 华东师范大学保研机试-2022-差分计数
代码
CPP
#include <bits/stdc++.h>
using namespace std;
void solve() {
int n;
cin >> n;
vector<vector<int>> vec(2);
for (int i = 1; i <= n; ++i) {
int x; cin >> x;
vec[x].emplace_back(i);
}
vector<vector<int>> pre(2, vector<int>(n + 1, 0));
for (int c = 0; c < 2; ++c) {
int j = 1;
for (int i = 0; i < vec[c].size(); ++i) {
while (j <= vec[c][i]) {
// 计算 c 阵营中小于等于 j 的数的个数
pre[c][j] = pre[c][j - 1];
j += 1;
}
pre[c][j - 1] += 1;
}
while (j <= n) {
pre[c][j] = pre[c][j - 1];
j += 1;
}
}
vector<int> ans(n);
for (int c = 0; c < 2; ++c) {
for (int i = 0; i < vec[c].size(); ++i) {
int j = vec[c][i];
// 计算本阵营中大于 vec[c][i] 的数的个数
ans[j - 1] += int(vec[c].size()) - 1 - i;
// 计算敌方阵营中小于 vec[c][i] 的数的个数
ans[j - 1] += pre[c ^ 1][j - 1];
}
}
for (int i = 0; i < n; ++i) cout << ans[i] << " \n"[i + 1 == n];
}
int main()
{
int T;
cin >> T;
while (T--) solve();
return 0;
}
python
T = int(input()) for _ in range(T): n = int(input()) vec = [[], []] x = list(map(int, input().split())) for i in range(1, n + 1): vec[x[i - 1]].append(i) pre = [[0] * (n + 1) for _ in range(2)] for c in range(2): j = 1 for i in range(len(vec[c])): while j <= vec[c][i]: # 计算 c 阵营中小于等于 j 的数的个数 pre[c][j] = pre[c][j - 1] j += 1 pre[c][j - 1] += 1 while j <= n: pre[c][j] = pre[c][j - 1] j += 1 ans = [0] * n for c in range(2): for i in range(len(vec[c])): j = vec[c][i] # 计算本阵营中大于 vec[c][i] 的数的个数 ans[j - 1] += len(vec[c]) - 1 - i # 计算敌方阵营中小于 vec[c][i] 的数的个数 ans[j - 1] += pre[c ^ 1][j - 1] print(*ans)
Java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int t = scanner.nextInt();
while (t-- > 0) {
int n = scanner.nextInt();
int[][] vec = new int[2][];
vec[0] = new int[n + 1];
vec[1] = new int[n + 1];
int[] count = new int[2];
for (int i = 1; i <= n; ++i) {
int x = scanner.nextInt();
vec[x][++count[x]] = i;
}
int[][] pre = new int[2][];
pre[0] = new int[n + 1];
pre[1] = new int[n + 1];
for (int c = 0; c < 2; ++c) {
int j = 1;
for (int i = 1; i <= count[c]; ++i) {
// 计算 c 阵营中小于等于 j 的数的个数
while (j <= vec[c][i]) {
pre[c][j] = pre[c][j - 1];
++j;
}
++pre[c][j - 1];
}
while (j <= n) {
pre[c][j] = pre[c][j - 1];
++j;
}
}
int[] ans = new int[n];
for (int c = 0; c < 2; ++c) {
for (int i = 1; i <= count[c]; ++i) {
int j = vec[c][i];
// 计算本阵营中大于 vec[c][i] 的数的个数
ans[j - 1] += count[c] - i;
// 计算敌方阵营中小于 vec[c][i] 的数的个数
ans[j - 1] += pre[c ^ 1][j - 1];
}
}
for (int i = 0; i < n; ++i) {
System.out.print(ans[i]);
if (i + 1 == n) {
System.out.println();
} else {
System.out.print(" ");
}
}
}
}
}
Go
package main
import (
"fmt"
)
func main() {
var T int
fmt.Scan(&T)
for i := 0; i < T; i++ {
var n int
fmt.Scan(&n)
vec := make([][]int, 2)
vec[0] = make([]int, n+1)
vec[1] = make([]int, n+1)
count := make([]int, 2)
for j := 1; j <= n; j++ {
var x int
fmt.Scan(&x)
count[x]++
vec[x][count[x]] = j
}
pre := make([][]int, 2)
pre[0] = make([]int, n+1)
pre[1] = make([]int, n+1)
for c := 0; c < 2; c++ {
j := 1
for i := 1; i <= count[c]; i++ {
// 计算 c 阵营中小于等于 j 的数的个数
for j <= vec[c][i] {
pre[c][j] = pre[c][j-1]
j++
}
pre[c][j-1]++
}
for j <= n {
pre[c][j] = pre[c][j-1]
j++
}
}
ans := make([]int, n)
for c := 0; c < 2; c++ {
for i := 1; i <= count[c]; i++ {
j := vec[c][i]
// 计算本阵营中大于 vec[c][i] 的数的个数
ans[j-1] += count[c] - i
// 计算敌方阵营中小于 vec[c][i] 的数的个数
ans[j-1] += pre[c^1][j-1]
}
}
for i := 0; i < n; i++ {
if i == n-1 {
fmt.Println(ans[i])
} else {
fmt.Printf("%d ", ans[i])
}
}
}
}
Js
process.stdin.resume();
process.stdin.setEncoding('utf-8');
let input = '';
process.stdin.on('data', (data) => {
input += data;
return;
});
process.stdin.on('end', () => {
const lines = input.trim().split('\n');
let index = 0;
const T = parseInt(lines[index++]);
for (let i = 0; i < T; i++) {
const n = parseInt(lines[index++]);
const vec = [[], []];
const x = lines[index++].split(' ').map(Number);
for (let j = 1; j <= n; j++) {
vec[x[j - 1]].push(j);
}
const pre = [[], []];
for (let c = 0; c < 2; c++) {
let j = 1;
// 计算 c 阵营中小于等于 j 的数的个数
for (let i = 0; i < vec[c].length; i++) {
while (j <= vec[c][i]) {
pre[c][j] = pre[c][j - 1] || 0;
j += 1;
}
pre[c][j - 1] = (pre[c][j - 1] || 0) + 1;
}
while (j <= n) {
pre[c][j] = pre[c][j - 1] || 0;
j += 1;
}
}
const ans = new Array(n).fill(0);
for (let c = 0; c < 2; c++) {
for (let i = 0; i < vec[c].length; i++) {
const j = vec[c][i];
// 计算本阵营中大于 vec[c][i] 的数的个数
ans[j - 1] += vec[c].length - 1 - i;
// 计算敌方阵营中小于 vec[c][i] 的数的个数
ans[j - 1] += pre[c ^ 1][j - 1] || 0;
}
}
console.log(ans.join(' '));
}
});


















