【Nowcoder 1103A】复读数组
题目大意:
有一个长为 \(n\times k\) 的数组,它是由长为 \(n\) 的数组 \(A_1,A_2,\cdots,A_n\) 重复 \(k\) 次得到的。
定义这个数组的一个区间的权值为它里面不同的数的个数,现在,你需要求出对于这个数组的每个非空区间的权值之和。
正文:
有一个关键的性质:答案就是每一个数字能做贡献的区间数量之和。那么我们只用枚举最近的两个相同数字,然后用总区间减去两个数字之间的非空子区间个数即可。
代码:
const int N = 1e5 + 10;
const ll mod = 1e9 + 7;
inline ll Read()
{
ll x = 0, f = 1;
char c = getchar();
while (c != '-' && (c < '0' || c > '9')) c = getchar();
if (c == '-') f = -f, c = getchar();
while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
return x * f;
}
ll n, t;
ll m, a[N], ans, b[N];
vector <int> pos[N];
ll Cnt(ll l, ll r)
{
return (r - l + 1) * (r - l + 2) % mod * 500000004ll % mod;
}
int main()
{
n = Read(), m = Read();
for (int i = 1; i <= n; i++) b[i] = a[i] = Read();
sort (b + 1, b + 1 + n);
t = unique(b + 1, b + 1 + n) - b - 1;
for (int i = 1; i <= n; i++) pos[lower_bound(b + 1, b + 1 + t, a[i]) - b].push_back(i);
for (int i = 1; i <= t; i++)
{
int len = pos[i].size();
ll tmp = 0;
(tmp += (Cnt(1, pos[i][0] - 1) + Cnt(pos[i][len - 1] + 1, n)) % mod) %= mod;
for (int j = 1; j < len; j++)
(tmp += Cnt(pos[i][j - 1] + 1, pos[i][j] - 1) * m % mod) %= mod;
(tmp += Cnt(pos[i][len - 1] + 1, pos[i][0] + n - 1) * (m - 1) % mod) %= mod;
ans = (ans + Cnt(1, n * m % mod) - tmp) % mod;
}
printf ("%lld\n", (ans % mod + mod) % mod);
return 0;
}