为了更好的阅读体检,可以查看我的算法学习博客第二题-南北对决
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(' ')); } });