描述
题解
做这道题明显感觉智商不够用,只能说略懂略懂……套路太深,数论有些差了/(ㄒoㄒ)/~~不是看了大牛们的详解我断然无法弄懂这道题。
以下是官方题解:
对于一段区间l~r,其中一个数x对答案的贡献为(2x-l-r)次。
因此我们只要求出所有数对答案的贡献并累加起来即可。
将2x-l-r分为两部分,一部分为求2x的和,即为x左边与x右边相同的数的对数。
另一部分为l+r,将其拆开来,并记录前缀和,对于一个数a[i],我们需要维护的是Σk,Σs[i-1],Σs[i-1]*i
,以及a[i]出现的次数就可以了。
这里我们可以在枚举的同时,记录这些信息,并更新答案,就可以了。
复杂度为线性O(n)。
如果感觉这个不够详细,可以去看看zkGaia的blog,十分详细,虽然有的地方并不能悟透,建议这两个结合起来理解,因为我感觉这个博客里的题解讲得有些地方不是承上启下得太好,有点懵逼了我(@ο@) 当然,也要结合代码去好好理解,哎,我太笨了,是硬伤啊~~~
代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
const int MAXN = 3e6 + 10;
typedef unsigned int uint;
int n, lrk[MAXN], rrk[MAXN], pre[MAXN], nxt[MAXN], pos[MAXN];
uint a[MAXN], decA[MAXN], decB[MAXN], f[MAXN], g[MAXN], ans = 0;
void in(uint &w)
{
w = 0;
char c = getchar();
while (c > '9' || c < '0')
{
c = getchar();
}
while (c >= '0' && c <= '9')
{
w = w * 10 + c - '0';
c = getchar();
}
}
uint mult(uint a, uint b)
{
uint s = 0;
while (b)
{
if (b & 1)
{
s += a;
}
a += a;
b >>= 1;
}
return s;
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
in(a[i]);
}
memset(pos, 0, sizeof(pos));
for (int i = 1; i <= n; i++)
{
pre[i] = pos[a[i]];
pos[a[i]] = i;
lrk[i] = lrk[pre[i]] + 1;
decA[i] = decA[pre[i]] + pre[i];
}
memset(pos, 0, sizeof(pos));
for (int i = n; i >= 1; i--)
{
nxt[i] = pos[a[i]];
pos[a[i]] = i;
rrk[i] = rrk[nxt[i]] + 1;
decB[i] = decB[nxt[i]] + nxt[i];
}
for (int i = 1; i <= n; i++)
{
if (rrk[i] == 1)
{
nxt[i] = i + n;
pre[i + n] = i;
lrk[nxt[i]] = lrk[i] + 1;
decA[i + n] = decA[i] + i;
}
if (lrk[i] == 1)
{
pre[i] = i + n * 2;
nxt[i + n * 2] = i;
rrk[pre[i]] = rrk[i] + 1;
decB[i + n * 2] = decB[i] + i;
}
}
for (int i = 1; i <= n; i++)
{
f[i] = f[i - 1] + i * rrk[i] - decA[nxt[i - 1]];
}
for (int i = n; i >= 1; i--)
{
g[i] = g[i + 1] + i * lrk[i] - decB[pre[i + 1]];
}
for (int i = 1; i <= n; i++)
{
f[i] = f[i] + g[i] - i * 2;
}
memset(g, 0, sizeof(g));
memset(decA, 0, sizeof(decA));
for (int i = 1; i <= n; i++)
{
decA[i] = decA[pre[i]] + (pre[i] >= 1 && pre[i] <= n);
if (rrk[i] == 1)
{
decA[i + n] = decA[i] + 1;
}
}
for (int i = 1; i <= n; i++)
{
g[i] = g[i - 1] + rrk[i] - decA[nxt[i - 1]];
f[i] = mult(g[i] - 1, i) * 2 - f[i];
ans += mult(f[i], a[i]);
}
cout << ans << endl;
return 0;
}