题目描述
一条狭长的纸带被均匀划分出了 n 个格子,格子编号从 1 到 n。每个格子上都染了一种颜色 𝑐𝑜𝑙𝑜𝑟𝑖(用[1,m]当中的一个整数表示),并且写了一个数字 𝑛𝑢𝑏𝑒𝑟𝑖。
定义一种特殊的三元组:(x,y,z),其中 x,y,z 都代表纸带上格子的编号,这里的三元组要求满足以下两个条件:
-
𝑥,𝑦,𝑧 都是整数, 𝑥<𝑦<𝑧,𝑦−𝑥=𝑧−𝑦;
-
𝑐𝑜𝑙𝑜𝑟𝑥=𝑐𝑜𝑙𝑜𝑟𝑧。
满足上述条件的三元组的分数规定为 (x+z)∗(𝑛𝑢𝑚𝑏𝑒𝑟𝑥+𝑛𝑢𝑚𝑏𝑒𝑟𝑧)。整个纸带的分数规定为所有满足条件的三元组的分数的和。这个分数可能会很大,你只要输出整个纸带的分数除以 10007 所得的余数即可。
输入描述
第一行是用一个空格隔开的两个正整数 𝑛,𝑚,𝑛 代表纸带上格子的个数,𝑚 代表纸带上颜色的种类数。
第二行有 𝑛 个用空格隔开的正整数,第 𝑖 个数字 𝑛𝑢𝑚𝑏𝑒𝑟𝑖 代表纸带上编号为 𝑖 的格子上面写的数字。
第三行有 𝑛 个用空格隔开的正整数,第 𝑖 个数字 𝑐𝑜𝑙𝑜𝑟𝑖 代表纸带上编号为 𝑖 的格子染的颜色。
其中, 1≤𝑛≤105,1≤𝑚≤105,1≤𝑐𝑜𝑙𝑜𝑟𝑖≤𝑚,1≤𝑛𝑢𝑚𝑏𝑒𝑟𝑖≤105。
输出描述
输出共一行,一个整数,表示所求的纸带分数除以 10007 所得的余数。
示例 1
输入
6 2
5 5 3 2 2 2
2 2 1 1 2 1
输出
82
样例说明
纸带如题干中的图所示。
所有满足条件的三元组为:(1, 3, 5), (4, 5, 6)。
所以纸带的分数为(1 + 5) ∗ (5 + 2) + (4 + 6) ∗ (2 + 2) = 42 + 40 = 82。
示例 2
输入
15 4
5 10 8 2 2 2 9 9 7 7 5 6 4 2 4
2 2 3 3 4 3 3 2 4 4 4 4 1 1 1
输出
1388
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
解析:
暴力求解法:
时间复杂度过高,过不了。
#include <iostream>
#include<vector>
using namespace std;
typedef long long ll;
const ll MAX = 1e5+4;
const ll M = 1e4 + 7;
ll sum = 0;
ll numberi[MAX];
ll colori[MAX];
int main()
{
ll n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> numberi[i];
}
for (int i = 1; i <= n; i++)
{
cin >> colori[i];
}
//通过y−x=z−y 2y=x+z 奇数一组 偶数一组 符合要求
for (int i = 1; i <= n; i += 2)//奇数组
{
for (int j = i + 2; j <= n; j += 2)
{
if (colori[i] == colori[j])
{
sum = (sum + (i + j) * (numberi[i] + numberi[j]) % M) % M;
}
}
}
for (int i = 2; i <= n; i += 2)//偶数组
{
for (int j = i + 2; j <= n; j += 2)
{
if (colori[i] == colori[j])
{
sum = (sum + (i + j) * (numberi[i] + numberi[j]) % M) % M;
}
}
}
cout << sum << endl;
return 0;
}
公式转化法:
#include <iostream>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
const ll MAX = 1e5+4;
const ll M = 1e4 + 7;
ll sum = 0;
ll numberi[MAX];
ll colori[MAX];
map<ll, vector<ll>>mp;//颜色编号 格子编号
int main()
{
ll n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> numberi[i];
}
for (int i = 1; i <= n; i++)
{
cin >> colori[i];
mp[colori[i]].push_back(i);//通过颜色分开 相同颜色的一组
}
for (int i = 1; i <= m; i++)//颜色的总数
{
ll i1 = 0, i2 = 0;
ll ax1 = 0, ax2 = 0;
ll a_sum1 = 0, a_sum2 = 0;
ll x_sum1 = 0, x_sum2 = 0;
if (mp[i].size())//该颜色下不为空
{
for (auto j = mp[i].begin(); j != mp[i].end(); j++)
{
if (*j % 2)//奇数一组
{
i1++;
ax1 = (ax1 + *j * numberi[*j] % M) % M;
a_sum1 =(a_sum1+ *j)%M;
x_sum1 = (x_sum1 + numberi[*j])%M;
}
else//偶数一组
{
i2++;
ax2 = (ax2 + *j * numberi[*j] % M) % M;
a_sum2 = (a_sum2 + *j) % M;
x_sum2 = (x_sum2 + numberi[*j]) % M;
}
}
if (i1 >= 2)
{
sum = (sum + (ax1 * (i1 - 2)) % M + a_sum1 * x_sum1 % M) % M;
}
if (i2 >= 2)
{
sum = (sum + (ax2 * (i2 - 2)) % M + a_sum2 * x_sum2 % M) % M;
}
}
}
cout << sum << endl;
return 0;
}