## 思路
首先,枚举两个端点显然很慢,我们先用 数组和 数组来存两个人出牌的所有情况。
将 数组与 数组排序。
此时 数组和 数组的大小分别是 和 。直接一个个枚举显然是不行的,我们可以枚举 数组,然后二分 数组,找到大于 的第一个数 。因为 数组满足单调性(排序过),所以只要 。
不会费马小定理的同学可以去这题学习一下,这里就不再证明。最后输出的答案为 。此时 ,。因为 很大,需要使用快速幂。
一定要开 `long long`!
## 关键部分代码
#define int long long
int p = 998244353;
//快速幂
int pow(int n,int m) {
int ans = 1;
while(m) {
if(m & 1) {
ans *= n;
ans %= p;
}
n *= n;
n %= p;
m >>= 1;
}
return ans;
}
//求逆元
int niyuan(int n) {
return pow(n,p - 2);
}
int n,m,a[2005],b[2005],c[4000005],d[4000005],cnt = 0,cnt1 = 0,ans = 0;
signed main() {
n = read(),m = read();
int sum = n * (n + 1) / 2;
sum %= p;
sum *= m * (m + 1) / 2;
sum %= p;
//前缀和
for(int i = 1;i <= n;i++) a[i] = read() + a[i - 1];
for(int i = 1;i <= m;i++) b[i] = read() + b[i - 1];
for(int i = 1;i <= n;i++) {
for(int j = i;j <= n;j++) {
c[++cnt] = a[j] - a[i - 1];
}
}
for(int i = 1;i <= m;i++) {
for(int j = i;j <= m;j++) {
d[++cnt1] = b[j] - b[i - 1];
}
}
sort(c + 1,c + cnt + 1);
sort(d + 1,d + cnt1 + 1);
//枚举 d 数组
for(int i = 1;i <= cnt1;i++) {
int l = 1,r = cnt,mid;
//二分 c 数组
while(l < r) {
mid = (l + r) >> 1;
if(c[mid] > d[i]) r = mid;
else l = mid + 1;
}
if(c[l] > d[i]) {
ans += (cnt - l + 1);
}
ans %= p;
}
write(ans * niyuan(sum) % p);
return 0;
}