(T3)矩阵
题目背景:
14 已经想不出新颖的题目背景了,所以他准备用序列来构造矩阵。
题目描述:
WY (机房巨佬) 给了 14 一个长度为
n
n
n 的序列
a
a
a 和一个长度为
m
m
m 的序列
b
b
b。
14 玩序列玩腻了,准备用这两个序列构造出一个 n × m n\times m n×m 的矩阵 c。
14 规定 c i , j = a i × b i c_{i,j}=a_i \times b_i ci,j=ai×bi,14 是一个好奇的小朋友,
他想知道在这个矩阵中有多少个子矩阵的元素之和为 k k k。
其中 k k k 为 14 给定的一个常数。
输入格式:
输入第一行包含三个整数 n , m , k n,m,k n,m,k,表示序列 a a a 的长度,序列 b b b 的长度以及 14 给出的常数。
输入第二行包含 n n n 个整数,表示序列 a a a 。
输入第三行包含 m m m 个整数,表示序列 b b b 。
输出格式:
输出只有一行,表示符合条件的子矩阵个数。
样例输入:
3 4 20
2 3 5
4 6 3 2
样例输出:
4
题解:
对于一个左上角为 a i , b i a_i,b_i ai,bi,右下角为 a j , b j a_j,b_j aj,bj,的矩形里面的元素和
是等于 ( ∑ k = i j a k ) × ( ∑ t = i j b t ) (\sum\limits_{k=i}^{j}a_k) \times (\sum\limits_{t=i}^{j}b_t) (k=i∑jak)×(t=i∑jbt)
因为是 i i i 至 j j j 范围中间所有的 a a a 数组里值的和
就可以先求一个前缀和
b b b 数组同理
保证可以二分的条件:
因为所有的 a i , b i a_i,b_i ai,bi 值都是 1 e 9 ≥ a i , b i ≥ 0 1e9\ge a_i,b_i \ge0 1e9≥ai,bi≥0
所以在确定左端点的情况下它是单调递增的。
把 k k k 的所有因数求出来(不会太多,据 l j s ljs ljs 所言最多240个左右)
预处理干完了开始主要部分:
先对 a a a 数组枚举左端点在枚举 k k k 的所有因数
然后对 i i i 到 n n n 进行二分
用之前求好的前缀和把 a i a_i ai 到 a [ a[ a[ 二分的值 ] ] ]的和调出来看是否等于枚举的 k k k 的因数
b b b 数组同理
然后就完了^_^
上代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
LL x[1000005];
LL y[1000005];
LL vis[1000005];
LL sum[10005];
LL cnt;
LL a[50005];
LL b[50005];
void read(LL& x) {
int f = 1;
x = 0;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
x *= 10;
x += c - '0';
c = getchar();
}
x *= f;
}
int main() {
LL n, m, k;
read(n);
read(m);
read(k);
for (int i = 1; i <= k; i++) {
if (k % i == 0) {
sum[++cnt] = i;
}
}
for (int i = 1; i <= n; i++) {
read(a[i]);
a[i] += a[i - 1];
}
for (int i = 1; i <= m; i++) {
read(b[i]);
b[i] += b[i - 1];
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= cnt; j++) {
LL l = i, r = n;
LL t = 0;
while (l < r - 1) {
LL mid = (l + r) / 2;
if (a[mid] - a[i - 1] == sum[j]) {
x[sum[j]]++;
t = 1;
break;
} else if (a[mid] - a[i - 1] > sum[j]) {
r = mid - 1;
continue;
} else {
l = mid + 1;
continue;
}
}
if (t == 0) {
if (a[l] - a[i - 1] == sum[j])
x[sum[j]]++;
if (a[l + 1] - a[i - 1] == sum[j])
x[sum[j]]++;
}
}
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= cnt; j++) {
LL l = i, r = n;
LL t = 0;
while (l < r - 1) {
LL mid = (l + r) / 2;
if (b[mid] - b[i - 1] == sum[j]) {
t = 1;
y[sum[j]]++;
break;
} else if (b[mid] - b[i - 1] > sum[j]) {
r = mid - 1;
continue;
} else {
l = mid + 1;
continue;
}
}
if (t == 0) {
if (b[l] - b[i - 1] == sum[j])
y[sum[j]]++;
if (b[l + 1] - b[i - 1] == sum[j])
y[sum[j]]++;
}
}
}
LL ans = 0;
for (int i = 1; i <= cnt; i++) {
ans += x[sum[i]] * y[k / sum[i]];
}
printf("%lld", ans);
return 0;
}
Ac代码
只有 50 50 50 分不知道哪里错了