2021-08-09 SSL 模拟赛 T2
这道阴间的题目竟然也没有标题。
思路:
对于一个矩阵,我们设它的左上角为
[
x
1
,
y
1
]
[x_1,y_1]
[x1,y1],右下角为
[
X
2
,
Y
2
]
[X_2,Y_2]
[X2,Y2],那么这个矩阵的和为
a
[
x
1
]
∗
(
b
[
y
1
]
+
b
[
y
1
+
1
]
+
⋅
⋅
⋅
+
b
[
y
2
]
)
+
⋅
⋅
⋅
+
a
[
x
2
]
∗
(
b
[
y
1
]
+
b
[
y
1
+
1
]
+
⋅
⋅
⋅
+
b
[
y
2
]
)
a[x_1]*(b[y_1]+b[y_1+1]+···+b[y_2])+···+a[x_2]*(b[y_1]+b[y_1+1]+···+b[y_2])
a[x1]∗(b[y1]+b[y1+1]+⋅⋅⋅+b[y2])+⋅⋅⋅+a[x2]∗(b[y1]+b[y1+1]+⋅⋅⋅+b[y2])
=
∑
i
=
x
1
x
2
a
[
i
]
∗
∑
j
=
y
1
y
2
b
[
j
]
=\sum_{i=x_1}^{x_2}a[i]*\sum_{j=y_1}^{y_2}b[j]
=i=x1∑x2a[i]∗j=y1∑y2b[j]
我们发现,
x
1
,
x
2
x_1,x_2
x1,x2和
y
1
,
y
2
y_1,y_2
y1,y2之间没有什么直接的联系。
那么我们可以预处理出 y 的所有区间和,再去枚举
x
1
,
x
2
x_1,x_2
x1,x2。
然后我们利用前缀和可以很轻松的求出
a
[
x
1
]
—
—
a
[
x
2
]
a[x_1]——a[x_2]
a[x1]——a[x2]的区间和
然后我们用询问区间除去这个区间和,那么剩下的就是 y 坐标的取值范围了
因为我们已经预处理出了关于 y 的每个区间和,将其排序后进行二分查找在查询区间内的个数,累加即可。
伟大的
e
l
b
a
t
e
a
c
h
e
r
elba~~~teacher
elba teacher 给出的思路 (本人解法的来源):
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#define r register
#define rep(i,x,y) for(r ll i=x;i<=y;++i)
#define per(i,x,y) for(r ll i=x;i>=y;--i)
using namespace std;
typedef long long ll;
ll n,m,a[1200],b[1200];
ll L,R,mid,sa[1200],sb[1200];
ll c[1001*1001],top,le,ri,ans;
ll ask(ll le,ll ri)
{
//这两个是二分查找函数,非常方便不会用的可以自行上网搜索
ll x=lower_bound(c+1,c+top+1,le)-c; //返回第一个>= x 的值
ll y=upper_bound(c+1,c+top+1,ri)-c; //返回第一个 > y 的值
return y-x; //合法个数
}
void work()
{
rep(i,1,n) //枚举x1,x2
rep(j,i,n)
{
ll v=sa[j]-sa[i-1];
ll le=L/v,ri=R/v;
if(L%v) ++le; //注意除法时多出来的余数,左边界向上取整,右边界向下取整
ans+=ask(le,ri);
}
printf("%lld",ans);
}
int main()
{
scanf("%lld%lld%lld%lld",&n,&m,&L,&R);
rep(i,1,n)
{
scanf("%lld",&a[i]);
sa[i]=sa[i-1]+a[i];
}
rep(i,1,m)
{
scanf("%lld",&b[i]);
sb[i]=sb[i-1]+b[i];
}
rep(i,1,m)
rep(j,i,m)
c[++top]=sb[j]-sb[i-1]; //预处理出关于 y 的所有区间和
sort(c+1,c+top+1);
work();
return 0;
}