1 条题解
-
0
题解
原始网格 由数组 (长度 )和 (长度 )生成,其中 。其美丽值(所有元素之和)为:
$$B = \sum_{i=1}^n \sum_{j=1}^m a_i b_j = \left(\sum_{i=1}^n a_i\right) \cdot \left(\sum_{j=1}^m b_j\right) = S_a \cdot S_b $$记 ,。
当我们选择第 行和第 列置零时,移除的元素和为:
- 整行 :
- 整列 :
- 行列交叉点 被减两次,需加回:
因此操作后的美丽值 为:
$$X = S_a S_b - a_r S_b - S_a b_c + a_r b_c = (S_a - a_r)(S_b - b_c) $$问题转化为:对每个查询 ,判断是否存在 和 使得 。
关键观察:题目约束 。若 的绝对值大于 ,则因为乘积非零,,而 是整数,不可能成立。因此我们只需考虑绝对值在 以内的差值。
实现步骤:
- 计算 和 。
- 遍历数组 ,若 ( 取 ),根据正负分别记录在布尔数组
apos(正)或aneg(负)中。同理处理数组 得到bpos、bneg。 - 预处理所有可能的乘积:枚举 ,若乘积 ,则:
apos[i] && bpos[j]正乘积 可达,标记posspos[i*j] = true。aneg[i] && bneg[j]负负得正,标记posspos[i*j] = true。apos[i] && bneg[j]或aneg[i] && bpos[j]负乘积可达,标记possneg[i*j] = true。
- 对每个查询 :
- 若 且
posspos[x]为真,输出YES,否则NO。 - 若 且
possneg[-x]为真,输出YES,否则NO。
- 若 且
复杂度:预处理枚举乘积为调和级数 ,查询 ,总时间完全可行。
C++ 参考代码(依据标程):
#include <bits/stdc++.h> using namespace std; #define FOR(i,a,b) for (int i = (a); i < (b); ++i) #define F0R(i,a) FOR(i,0,a) #define int long long #define vt vector #define endl "\n" const int N = 4e5 + 5; bool apos[N], aneg[N], bpos[N], bneg[N], posspos[N], possneg[N]; signed main() { ios_base::sync_with_stdio(false); cin.tie(0); int n,m,q; cin >> n >> m >> q; vector<int> a(n), b(m); int asum = 0, bsum = 0; F0R(i, n) { cin >> a[i]; asum += a[i]; } F0R(i, m) { cin >> b[i]; bsum += b[i]; } F0R(i, n) { if(abs(asum-a[i]) < N) { if(asum-a[i] < 0) aneg[a[i]-asum] = true; else apos[asum-a[i]] = true; } } F0R(i, m) { if(abs(bsum-b[i]) < N) { if(bsum-b[i] < 0) bneg[b[i]-bsum] = true; else bpos[bsum-b[i]] = true; } } FOR(i, 1, N) { FOR(j, 1, N) { if(i * j > N) break; if(apos[i] && bpos[j]) posspos[i*j] = true; if(apos[i] && bneg[j]) possneg[i*j] = true; if(aneg[i] && bpos[j]) possneg[i*j] = true; if(aneg[i] && bneg[j]) posspos[i*j] = true; } } while(q--) { int x; cin >> x; if(x > 0) { if(posspos[x]) cout << "YES" << endl; else cout << "NO" << endl; } else { if(possneg[-x]) cout << "YES" << endl; else cout << "NO" << endl; } } return 0; }
- 1
信息
- ID
- 6675
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者