持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情
题目描述
这是代码源5月28日的div2每日一题
奶牛集会 - 题目 - Daimayuan Online Judge
题目描述
约翰的 n 头奶牛每年都会参加“哞哞大会”。
哞哞大会是奶牛界的盛事。集会上的活动很多,比如堆干草,跨栅栏,摸牛仔的屁股等等。
它们参加活动时会聚在一起,第 i 头奶牛的坐标为 xi,没有两头奶牛的坐标是相同的。
奶牛们的叫声很大,第 i 头和第 j 头奶牛交流,会发出 max{vi,vj}×|xi−xj| 的音量,其中 vi 和 vj 分别是第 i 头和第 j 头奶牛的听力。
假设每对奶牛之间同时都在说话,请计算所有奶牛产生的音量之和是多少。
输入格式
第 1 行:单个整数 n,1≤n≤3×10^4。
第 2 行到第 n+1 行:第 i+1 行有两个整数 vi 和 xi(1≤vi,xi≤3×10^4)。
输出格式
输出单个整数,表示所有奶牛产生的音量之和。
样例输入
4
3 1
2 5
2 6
4 3
样例输出
57
问题解析
1、暴力解法
数据量到了3*10 ^ 4,但是可以极限两层for循环暴力结束战斗(可能是数据比较弱罢)。
AC代码
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>
#define endl '\n'
#define int ll
typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 1e6;
int a[N];
vector<int>v[N];
signed main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n;
cin >> n;
vector<PII>v(n);
ll res = 0;
for (int i = 0; i < n; i++)cin >> v[i].first >> v[i].second;
for (int i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++)
{
res += max(v[i].first, v[j].first) * abs(v[i].second - v[j].second);
}
}
cout << res;
return 0;
}
2、线段树解法(树状数组也可)
首先我们看式子是 max{vi,vj}×|xi−xj| ,那么我们可以先按照vi把所有牛排序,这样我们就可以不用算max了,如果从小到大排序,那就是vj*|xi−xj| ,如果从大到小排序,就是**vi |xi−xj|* 。
然后我们看|xi−xj|,如果当前的 xi<xj ,那就是xj-xi;反之是xi-xj。这个值是根据当前两个数的关系来的。
处理他我用的是线段树,因为x的值范围是1≤xi≤3×10^4,那我们就开个子节点为3×10^4的线段树,初始都为0,那么小于xi的点,就是在区间1xi这一部分,对应的大于xi的点在区间xi3*10^4这段区间,我们只要算一下这两段的区间和,再根据区间里点的数目,就可以很快的算出这个牛和其它牛的音量之和,然后根据当前xi的值把这个点插入线段树中。为了方便我是将牛先按照vi升序排序,这样确保后面的牛的vi大于之前的vi。
AC代码
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>
#define endl '\n'
#define int ll
typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 4e4;
PII f[4 * N];
bool cmp(PII a, PII b)
{
return a.first < b.first;
}
void add(int k, int l, int r, int x)
{
if (l == r)
{
f[k].first += x;
f[k].second++;
return ;
}
int m = (l + r) / 2;
if (x <= m)add(k + k, l, m, x);
else add(k + k + 1, m + 1, r, x);
f[k].first = f[k + k].first + f[k + k + 1].first;
f[k].second = f[k + k].second + f[k + k + 1].second;
}
PII calc(int k, int l, int r, int x, int y)
{
if (l == x && r == y)
{
return f[k];
}
int m = (l + r) / 2;
if (y <= m)return calc(k + k, l, m, x, y);
else
if (x > m)return calc(k + k + 1, m + 1, r, x, y);
else
{
PII t;
auto a = calc(k + k, l, m, x, m);
auto b = calc(k + k + 1, m + 1, r, m + 1, y);
t.first = a.first + b.first;
t.second = a.second + b.second;
return t;
}
}
signed main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n;
cin >> n;
vector<PII>v(n);
ll res = 0, mx = 0;
for (int i = 0; i < n; i++)cin >> v[i].first >> v[i].second, mx = max(mx, v[i].second);
sort(v.begin(), v.end(), cmp);
for (int i = 0; i < n; i++)
{
auto a = calc(1, 1, mx, 1, v[i].second);
auto b = calc(1, 1, mx, v[i].second, mx);
res += v[i].first * (a.second * v[i].second - a.first);
res += v[i].first * (b.first - b.second * v[i].second);
add(1, 1, mx, v[i].second);
}
cout << res << endl;
return 0;
}