题目链接:点击打开链接
解法:
这个题首先考虑一个简单情况:对于区间[x,y],权值为多少。
容易写出公式:F[x , y] = S[y] - S[x-1] - (sum[y]-sum[x-1])*(x-1)+sum[x-1]*(y-x+1)
其中S[x]表示 从第一个元素到第x个元素的 所有有序二元组的和(题目中定义的),sum表示前缀和
整理一下就是:F[x , y] = S[y] - S[x-1] - sum[y]*(x-1) + sum(x-1)*y
这里要求的是所有a[x] == a[y]这样的区间和,注意到题目所有的数字都在10^6以内,所以可以开几个数组去维护每一个数字对应的信息。
继续对写出的式子进行讨论,假如对于当前给定的y,有多个x 满足a[x] == a[y]
答案就是
sigma F[x,y] = ct * S[y] - sigma S[x-1] - sum[y] * sigma (x-1) + sigma sum[x-1]* y
红色的部分就是需要维护的部分
开4个数组,对每个红字的部分,以数字为下标进行维护。
边扫描边维护。时间复杂度O(n)
注意mod
做这种题还是先写出公式,会思路清晰很多。
#include<iostream>
#include<string.h>
#include<string>
#include<algorithm>
#include<stdio.h>
#define LL long long int
using namespace std;
const int maxn = 1100000;
LL mod = ( (1LL)<<32);
LL ct[maxn];
LL sx[maxn];
LL lx[maxn];
LL ss[maxn];
int n;
void get(int &x)
{
char c = getchar(); x = 0;
while(c < '0' || c > '9') c = getchar();
while(c <= '9' && c >= '0') x = x*10+c-48, c = getchar();
}
void init()
{
memset(ct,0,sizeof(ct));
memset(sx,0,sizeof(sx));
memset(lx,0,sizeof(lx));
memset(ss,0,sizeof(ss));
}
int main()
{
while(cin>>n)
{
init();
LL sum = 0;
LL ts = 0;
LL ans = 0;
for(int i = 1;i<=n;i++)
{
int in ;
get(in);
LL tmp = (LL)in;
LL save = sum;
LL save2 = ts;
sum = (sum + (((i-1)*tmp)%mod - ts + mod)% mod)%mod;
ts += tmp;
ts %= mod;
LL x = ct[tmp]*sum%mod;
x = (x - sx[tmp] + mod) % mod;
x = (x - (lx[tmp]*ts%mod) + mod)%mod;
x = (x + i*ss[tmp]%mod) % mod;
ans = ans + x;
ans %= mod;
ct[tmp] ++;
sx[tmp] += save;
sx[tmp] %= mod;
lx[tmp] += (i-1);
lx[tmp] %= mod;
ss[tmp] += save2;
ss[tmp] %= mod;
}
printf("%lld\n",ans);
}
return 0;
}