我们发现规律是 x到y的距离==y到z的距离
并且x的颜色==z的颜色
所以我们只需要枚举y的位置就可以了,然后再想办法优化,暴力代码如下
时间复杂度是O(N^2)
for (int k = 2;k <= n;k++)
{//选择一个点作为y
int i = k - 1, j = k + 1;
while (i >= 1 && j <= n)
{
if(c[i]==c[j])
res = (res + (i + j) * (a[i]+a[j])) % mod;
i--, j++;
}
}
怎么优化?
优化其实就是要发现一些关于题目的性质
贪心,前缀和,差分,数学...都可以被用来优化
我们发现一个点z如果存在另一个点x满足性质
我们发现性质
1.三元组的取值和y无关,只与x,z有关
2.x,z的颜色相同,并且他们的奇偶性相同(因为要确保中间有奇数个点)
3.三元组的寻找可以进行优化,如下
三元组的优化
由于三元组的计算和y无关,所以我们只需要枚举z元素,然后找到在他之前所有可以取的x元素就可以了
更新res操作如下
res = (res + (ll)cnt[col][i % 2][0] * a[i]) % mod; //Σx*num_z
res = (res + (ll)cnt[col][i % 2][1] * i) % mod; //Σnum_x*z
res = (res +(ll) cnt[col][i % 2][2]) % mod; //Σnum_x*x
res = (res + (ll)cnt[col][i % 2][3] * i * a[i]) % mod; //z*num_z
更新前缀和数组如下
cnt[col][i % 2][0] = (cnt[col][i % 2][0] + i) % mod;
cnt[col][i % 2][1] = (cnt[col][i % 2][1] + a[i]) % mod;
cnt[col][i % 2][2] = (cnt[col][i % 2][2] +(ll) i * a[i]) % mod;
cnt[col][i % 2][3]++;
完整代码如下
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100050;
const int mod = 10007;
int a[N]; //数据数组
int c[N]; //颜色数组
typedef long long ll;
ll cnt[N][2][4];
ll res;
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1;i <= n;i++)
cin >> a[i]; //输入数据
for (int i = 1;i <= n;i++)
cin >> c[i]; //输入颜色
//处理前缀和
//注意要颜色相同,奇偶性相同
for (int i = 1;i <= n;i++)
{
//以下是更新res值
int col = c[i];
//********注意这里的乘积可能超过1e9,一定要全部开ll,否则会wa掉
res = (res + (ll)cnt[col][i % 2][0] * a[i]) % mod; //Σx*num_z
res = (res + (ll)cnt[col][i % 2][1] * i) % mod; //Σnum_x*z
res = (res +(ll) cnt[col][i % 2][2]) % mod; //Σnum_x*x
res = (res + (ll)cnt[col][i % 2][3] * i * a[i]) % mod; //z*num_z
//[3]表示n
//以下是更新前缀和数组
cnt[col][i % 2][0] = (cnt[col][i % 2][0] + i) % mod;
cnt[col][i % 2][1] = (cnt[col][i % 2][1] + a[i]) % mod;
cnt[col][i % 2][2] = (cnt[col][i % 2][2] +(ll) i * a[i]) % mod;
cnt[col][i % 2][3]++;
}
cout << res % mod;
}