题目
思路
双指针。
分别分析
f
(
x
)
和
g
(
x
)
~f(x) 和 g(x)~
f(x)和g(x) 的性质
-
对
于
f
(
x
)
对于f(x)
对于f(x)
可 以 将 序 列 a 看 作 n 个 不 相 重 叠 且 连 续 的 区 间 。 第 i 个 区 间 为 [ a [ i ] , a [ i + 1 ] ) 第 i 个 区 间 中 所 有 的 数 的 函 数 值 f ( x ) = i 可以将序列a看作n个不相重叠且连续的区间。第i个区间为~[~a[i], ~~a[i + 1]~)\\ 第i个区间中所有的数的函数值f(x) =\bm{i} 可以将序列a看作n个不相重叠且连续的区间。第i个区间为 [ a[i], a[i+1] )第i个区间中所有的数的函数值f(x)=i -
对
于
g
(
x
)
对于g(x)
对于g(x)
定 义 : b [ i ] = i × r , 且 b [ i ] < = m 定义: b[i] = i \times r, 且b[i] <= m 定义:b[i]=i×r,且b[i]<=m
b [ 0 ] = 0 b [ 1 ] = r b [ 2 ] = 2 r ⋯ ⋯ b [ k − 1 ] = ( k − 1 ) r b [ k ] = m b[0] = 0\\b[1] = r\\b[2] = 2r\\\cdots\cdots\\b[k - 1] = (k - 1)r\\b[k] = m b[0]=0b[1]=rb[2]=2r⋯⋯b[k−1]=(k−1)rb[k]=m
同 理 , b 序 列 也 可 以 看 作 k 个 不 同 的 区 间 第 j 个 区 间 对 应 的 函 数 值 g ( x ) = j 同理,b序列也可以看作k个不同的区间\\第j个区间对应的函数值g(x) = \bm{j} 同理,b序列也可以看作k个不同的区间第j个区间对应的函数值g(x)=j
每次移动时,将当前指针的公共部分累加入ans中即可。具体细节看代码部分
第
一
次
求
得
[
0
,
a
[
i
]
)
的
贡
献
第一次求得[0, a[i])的贡献
第一次求得[0,a[i])的贡献
第
二
次
求
得
[
a
[
1
]
,
b
[
1
]
)
的
贡
献
第二次求得[a[1], b[1])的贡献
第二次求得[a[1],b[1])的贡献
第
三
次
求
得
[
b
[
1
]
,
a
[
2
]
)
的
贡
献
第三次求得[b[1], a[2])的贡献
第三次求得[b[1],a[2])的贡献
⋯
⋯
\cdots\cdots
⋯⋯
最
终
i
,
j
两
个
指
针
均
指
向
两
个
数
组
各
自
的
末
尾
(
a
[
n
+
1
]
与
b
[
k
]
)
\\最终i,j两个指针均指向两个数组各自的末尾(a[n + 1]与b[k])
最终i,j两个指针均指向两个数组各自的末尾(a[n+1]与b[k])
CODE
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e5 + 7;
ll a[N], b[N];
int main()
{
IOS;
ll n, m; cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> a[i];
a[n + 1] = m;
ll r = m / (n + 1);
ll k = 1;
for (; k * r < m; k++)
b[k] = k * r;
b[k] = m;
ll ans = 0;
int i = 1, j = 1;
while (i < n + 1 || j < k)//注意是“或”
{
if (a[i] < b[j])
{
ans += (min(a[i + 1], b[j]) - a[i]) * abs(j - 1 - i);
i++;
}
else if (a[i] > b[j])
{
ans += (min(a[i], b[j + 1]) - b[j]) * abs(i - 1 - j);
j++;
}
else
{
ans += (ll)(min(a[i + 1], b[j + 1]) - a[i]) * abs(i - j);
i++;
j++;
}
}
cout << ans << endl;
return 0;
}