[USACO] 2004 Open MooFest 奶牛集會
題目背景
MooFest, 2004 Open
題目描述
約翰的N 頭奶牛每年都會參加“哞哞大會”。哞哞大會是奶牛界的盛事。集會上的活動很
多,比如堆幹草,跨柵欄,摸牛仔的屁股等等。它們參加活動時會聚在一起,第i 頭奶牛的坐標為Xi,沒有兩頭奶牛的坐標是相同的。奶牛們的叫聲很大,第i 頭和第j 頭奶牛交流,會發出\(max{Vi, Vj}\) \(×\) \(|Xi ? Xj |\) 的音量,其中Vi 和Vj 分別是第i 頭和第j 頭奶牛的聽力。假設每對奶牛之間同時都在說話,請計算所有奶牛產生的音量之和是多少。
輸入輸出格式
輸入格式:
? 第一行:單個整數N,1 ≤ N ≤ 20000
? 第二行到第N + 1 行:第i + 1 行有兩個整數Vi 和Xi.
輸出格式:
? 單個整數:表示所有奶牛產生的音量之和
輸入輸出樣例
輸入樣例#1:
4
3 1
2 5
2 6
4 3
輸出樣例#1:
57
說明
樸素O(N2)
類似於歸並排序的二分O(N logN)
樹狀數組O(N logN)
Solution
首先本著打暴力的心情先打了個\(O(N^2)\),結果數組開小了,然後改了之後就A了???
Code\((N^2)\)
#include<bits/stdc++.h> #define lol long long #define Min(a,b) (a)<(b)?(a):(b) #define Max(a,b) (a)>(b)?(a):(b) using namespace std; const int N=2e5+10; void in(int &ans) { ans=0;int f=1; char i=getchar(); while(i<'0'||i>'9'){if(i=='-') f=-1; i=getchar();} while(i>='0'&&i<='9') ans=(ans<<3)+(ans<<1)+i-'0',i=getchar(); ans*=f; } int n,m; lol ans; int v[N],p[N]; int main() { in(n); for(int i=1;i<=n;i++) in(v[i]),in(p[i]); for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) ans+=(Max(v[i],v[j]))*(abs(p[i]-p[j])); } printf("%lld\n",ans); return 0; }
然後想正解,只有當一頭奶牛的比其他奶牛大時才有貢獻,所以我們把數據按照聽力排序之後就可以消除這一點,即當前奶牛不會對後面的奶牛造成影響,因為它的聽力沒有後面的奶牛好
那麽肯定是需要\(O(N)\)來枚舉奶牛的,怎麽快速算出它的貢獻呢?
設num[i]為x[i]及x[i]前面的奶牛的個數,sum[i]為x[i]前面奶牛的坐標之和
都是前綴和
用一個\(log n\)的數據結構來維護,樹狀數組\(or\)線段樹,復雜度\(O(N*logN)\)
註意:以下說的的之前都指的是在一頭奶牛的坐標之前,而不是序號之前
所以每次掃到一頭奶牛之後,它對答案的貢獻就是
(這頭奶牛之前的奶牛的數量\(*\)本頭奶牛的坐標-這頭奶牛之前的坐標的前綴和)\(*\)
也就是
\[((num[i-1]*x[i]-sum[i-1])+(sum[maxn]-sum[i])-(num[maxn]-num[i])*x[i])*v[i]\]
因為我們是一邊枚舉一邊統計,其中maxn為坐標的最大值,用sum[maxn]和num[maxn]來統計當前有多少頭奶牛
先統計再插入
這裏擺上樹狀數組的代碼
Code
#include<bits/stdc++.h>
#define lol long long
#define Min(a,b) (a)<(b)?(a):(b)
#define Max(a,b) (a)>(b)?(a):(b)
using namespace std;
const int N=2e5+10;
void in(int &ans)
{
ans=0;int f=1; char i=getchar();
while(i<'0'||i>'9'){if(i=='-') f=-1; i=getchar();}
while(i>='0'&&i<='9') ans=(ans<<3)+(ans<<1)+i-'0',i=getchar();
ans*=f;
}
int n,m,maxn;
lol ans;
struct node {
int v,x;
bool operator < (const node & a) const {
if(a.v==v) return x<a.x;
return v<a.v;
}
}sub[N];
lol num[N],sum[N];
inline int lowbit(int x)
{
return x&-x;
}
void add(int x,int a,lol *f) {
while(x<=maxn) {
f[x]+=a;
x+=lowbit(x);
}
}
lol check(int x,lol *f) {
lol ans=0;
while(x) {
ans+=f[x];
x-=lowbit(x);
}
return ans;
}
int main()
{
in(n);
for(int i=1;i<=n;i++) in(sub[i].v),in(sub[i].x),maxn=Max(maxn,sub[i].x);
sort(sub+1,sub+1+n);
for(int i=1;i<=n;i++) {
lol size,dist;
size=check(sub[i].x-1,num);
dist=check(sub[i].x-1,sum);
ans+=sub[i].v*(size*sub[i].x-dist);
size=check(maxn,num)-check(sub[i].x,num);
dist=check(maxn,sum)-check(sub[i].x,sum);
ans+=sub[i].v*(dist-size*sub[i].x);
add(sub[i].x,sub[i].x,sum);
add(sub[i].x,1,num);
}
printf("%lld\n",ans);
return 0;
}
博主蒟蒻,隨意轉載.但必須附上原文鏈接
http://www.cnblogs.com/real-l/
[USACO] 2004 Open MooFest 奶牛集會