[R17C]投票分组2
对于 的数据,,。
思路
把同学按编号每 个一组( 是 的因数),第 组()覆盖编号区间 。该组是否支持款式 ,取决于组内 的票数是否 严格多于 的票数,即 的个数 ,等价地写成 。
预处理前缀和 表示 中 的个数(约定 ),第 组中 的个数就是 , 得到。
的所有因数用 枚举(连同 一起收集),再从小到大排序。对每个因数 ,枚举 个组各做一次 判断。
复杂度
预处理前缀和 ;枚举因数 ;对每个因数 扫 个组,总开销 。整体 ,对 绰绰有余。
仓颉实现
import std.convert.*
import std.env.*
import std.collection.*
import std.sort.*
main(): Int64 {
let reader = getStdIn()
let n = Int64.parse(reader.readln().getOrThrow())
let a = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p: String => Int64.parse(p) })
// prefix sum of ones: pre[i] = a_1..a_i 中 1 的个数(1-indexed),pre[0]=0
let pre = Array<Int64>(n + 1, { _ => 0 })
var s = 0
for (i in 0..n) {
if (a[i] == 1) {
s = s + 1
}
pre[i + 1] = s
}
// collect divisors of n
let divs = ArrayList<Int64>()
var i = 1
while (i * i <= n) {
if (n % i == 0) {
divs.add(i)
if (i != n / i) {
divs.add(n / i)
}
}
i = i + 1
}
sort(divs)
let sb = StringBuilder()
for (k in divs) {
// groups: g = 0 .. (n/k - 1), range [g*k+1, (g+1)*k]
// ones in group g = pre[(g+1)*k] - pre[g*k]
// supports 1 if ones*2 > k
var cnt = 0
var g = 0
let groups = n / k
while (g < groups) {
let ones = pre[(g + 1) * k] - pre[g * k]
if (ones * 2 > k) {
cnt = cnt + 1
}
g = g + 1
}
sb.append(cnt)
sb.append('\n')
}
print(sb.toString())
return 0
}