题目
思路
这道题我们对每个数考虑贡献。
设last为上一个当前数出现的位置。
显然可得:
(
i
−
l
a
s
t
i
−
1
)
+
(
n
−
i
)
+
(
i
−
l
a
s
t
i
−
1
)
∗
(
n
−
i
)
+
1
(i-last_i-1)+(n-i)+(i-last_i-1)*(n-i)+1
(i−lasti−1)+(n−i)+(i−lasti−1)∗(n−i)+1
因式分解可得:
(
i
−
l
a
s
t
i
)
(
n
−
i
+
1
)
(i-last_i)(n-i+1)
(i−lasti)(n−i+1)
把范围扩大到
n
×
k
n\times k
n×k
那我们可以把相同相对位置的数一起算:
(
i
−
l
a
s
t
i
)
(
k
n
−
i
+
1
)
+
(
i
−
l
a
s
t
i
)
(
k
n
−
i
−
n
+
1
)
+
…
+
(
i
−
l
a
s
t
i
)
(
k
n
−
i
−
2
×
n
+
1
)
(i-last_i)(kn-i+1)+(i-last_i)(kn-i-n+1)+…+(i-last_i)(kn-i-2\times n+1)
(i−lasti)(kn−i+1)+(i−lasti)(kn−i−n+1)+…+(i−lasti)(kn−i−2×n+1)
化简得:
(
i
−
l
a
s
t
i
)
(
k
2
n
−
k
i
−
n
×
k
(
k
−
1
)
2
+
k
)
(i-last_i)(k^2n-ki-n\times \displaystyle\frac{k(k-1)}{2}+k)
(i−lasti)(k2n−ki−n×2k(k−1)+k)
这样就可以
O
(
n
)
O(n)
O(n) 求答案.。
注意特判第一个区间的情况。
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const long long mod=1e9+7;
long long n,k,a[1000010],b[1000010],a2[1000010];
long long v[1000010],last[1000010];
long long ans;
int main()
{
freopen("loop.in","r",stdin);
freopen("loop.out","w",stdout);
scanf("%lld%lld",&n,&k);
for(long long i=1; i<=n; i++)
{
scanf("%lld",&a[i]);
b[i]=a[i];
}
sort(b+1,b+1+n);
long long qcn=unique(b+1,b+1+n)-b-1;
for(long long i=1; i<=n; i++)
a[i]=lower_bound(b+1,b+1+qcn,a[i])-b;
for(long long i=1; i<=n; i++)
a2[i]=a[i];
for(long long i=1; i<=n; i++)
a2[n+i]=a2[i];
for(long long i=1; i<=n*2; i++)
{
if(v[a2[i]])
last[i]=v[a2[i]];
v[a2[i]]=i;
}
for(long long i=1; i<=n; i++)
ans=(ans+((i+n-last[i+n]+mod)%mod*(((n*(k-1)%mod*(k-1))%mod-i*(k-1)%mod-n*((((k-1)*(k-2)/2))%mod)+k-1+mod))%mod)%mod)%mod;
memset(v,0,sizeof(v));
memset(last,0,sizeof(last));
for(long long i=1; i<=n; i++)
{
if(v[a[i]])
last[i]=v[a[i]];
v[a[i]]=i;
}
for(long long i=1; i<=n; i++)
ans=(ans+(i-last[i])*(n*k-i+1)%mod)%mod;
printf("%lld",ans);
return 0;
}