1、POJ 1990 MooFest
http://acm.pku.edu.cn/JudgeOnline/problem?id=1990
枚举的化肯定超时。算法魅力我个人认为在于减少普通算法的重复计算。本题中如果枚举,会不断重复计算每个牛声音小的牛之间的距离差。如果我们知道比当前牛声音小的牛的个数count和距离之和total。那么我们可以利用ans+= 1LL * cow[i].vol* (count * cow[i].x - total + alltotal - total - (i-count-1)*cow[i].x);其中alltotal是距离总和,alltotal- total - (i-count-1)*cow[i].x计算的是距离比他大的牛的距离差, count* cow[i].x- total是距离比他小的距离差。count和total可以用两个树状数组维护。
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int MAX = 20000 + 10;
int n;
struct node
{
int vol;
int x;
}cow[MAX];
int c1[MAX], c2[MAX];
bool operator<(const node&a, const node&b)
{
return a.vol < b.vol || a.vol == b.vol && a.x < b.x;
}
int lowbit(int x)
{
return x&(-x);
}
void update(int x, int v, int type)
{
while (x<MAX)
{
if (type == 1)
{
c1[x] += v;
}
else
{
c2[x] += v;
}
x+=lowbit(x);
}
}
int getsum(int x, int type)
{
int sum = 0;
while (x)
{
if (type == 1)
{
sum += c1[x];
}
else
{
sum += c2[x];
}
x-=lowbit(x);
}
return sum;
}
int main()
{
int i;
int count, total, alltotal;
__int64 ans;
while (scanf("%d", &n) == 1)
{
alltotal = 0;
ans = 0;
memset(c1, 0, sizeof(c1));
memset(c2, 0, sizeof(c2));
for (i=1; i<=n; i++)
{
scanf("%d%d", &cow[i].vol, &cow[i].x);
}
sort(cow+1, cow+n+1);
for (i=1; i<=n; i++)
{
//printf("%d %d\n", cow[i].vol, cow[i].x);
count = getsum(cow[i].x-1, 1);
total = getsum(cow[i].x-1, 2);
ans += 1LL * cow[i].vol * (count * cow[i].x - total + alltotal - total - (i-count-1)*cow[i].x);
alltotal += cow[i].x;
update(cow[i].x, 1, 1);
update(cow[i].x, cow[i].x, 2);
}
printf("%I64d\n", ans);
}
}
2、Hdu 3015 Disharmony Trees
http://acm.hdu.edu.cn/showproblem.php?pid=3015
跟上题方法相同,只要按它的要求离散化后,按高度降序排序,套用上题二个树状数组的方法即可。
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int MAX = 100000 + 10;
int n;
struct node1
{
int h;
int x;
int id;
}tree[MAX];
struct node2
{
int rankx;
int rankh;
}rank[MAX];
int c1[MAX], c2[MAX];
bool cmph(const node1&a, const node1&b)
{
return a.h<b.h;
}
bool cmpx(const node1&a, const node1&b)
{
return a.x<b.x;
}
bool cmpr(const node2&a, const node2&b)
{
return a.rankh>b.rankh;
}
int lowbit(int x)
{
return x&(-x);
}
void update(int x, int v, int type)
{
while (x<=n)
{
if (type == 1)
{
c1[x] += v;
}
else
{
c2[x] += v;
}
x+=lowbit(x);
}
}
int getsum(int x, int type)
{
int sum = 0;
while (x)
{
if (type == 1)
{
sum += c1[x];
}
else
{
sum += c2[x];
}
x-=lowbit(x);
}
return sum;
}
int main()
{
int i;
int count, total, alltotal, r;
__int64 ans;
while (scanf("%d", &n) == 1)
{
alltotal = 0;
ans = 0;
memset(c1, 0, sizeof(c1));
memset(c2, 0, sizeof(c2));
for (i=1; i<=n; i++)
{
scanf("%d%d", &tree[i].x, &tree[i].h);
tree[i].id = i;
}
sort(tree+1, tree+n+1,cmpx);
r = 1;
rank[tree[1].id].rankx = 1;
for (i=2; i<=n; i++)
{
if (tree[i].x!=tree[i-1].x)
{
r=i;
rank[tree[i].id].rankx = i;
}
else
{
rank[tree[i].id].rankx = r;
}
}
sort(tree+1, tree+n+1,cmph);
r = 1;
rank[tree[1].id].rankh = 1;
for (i=2; i<=n; i++)
{
if (tree[i].h!=tree[i-1].h)
{
r=i;
rank[tree[i].id].rankh = i;
}
else
{
rank[tree[i].id].rankh = r;
}
}
sort(rank+1, rank+n+1,cmpr);
for (i=1; i<=n; i++)
{
//printf("%d %d\n", rank[i].rankx, rank[i].rankh);
count = getsum(rank[i].rankx-1, 1);
total = getsum(rank[i].rankx-1, 2);
ans += 1LL * rank[i].rankh * (count * rank[i].rankx - total + alltotal - total - (i-count-1)*rank[i].rankx);
alltotal += rank[i].rankx;
update(rank[i].rankx, 1, 1);
update(rank[i].rankx, rank[i].rankx, 2);
}
printf("%I64d\n", ans);
}
}
3、HOJ 2430 Counting the algorithms
http://acm.hit.edu.cn/hoj/problem/view?id=2430
贪心,如果是两个包含的区间则先删除外边的最优。如果是交叉区间的情况,无论先删哪个,答案都是一样的。所以采取如下策略,从左边向右边,一个一个删除。至于统计动态的两个相邻元素之间的数目,可以使用树状数组。(这段语句引用于:http://blog.csdn.net/hyogahyoga/article/details/8041549)
/*This Code is Submitted by 1043041006 for Problem 2430 at 2013-04-05 10:23:52*/
#include <stdio.h>
#include <string.h>
#define DEBUGE 0
const int MAX = 100000 * 2 + 10;
int n;
int a[MAX], c[MAX], begin[MAX], end[MAX];
bool flag[MAX];
int lowbit(int x)
{
return x&(-x);
}
void update(int x, int v)
{
while (x<=2*n)
{
c[x] +=v;
x+=lowbit(x);
}
}
int getsum(int x)
{
int sum = 0;
while (x)
{
sum += c[x];
x -= lowbit(x);
}
return sum;
}
int main()
{
int i, ans = 0;
while(scanf("%d", &n) == 1)
{
ans = 0;
memset(flag, 0, sizeof(flag));
memset(c, 0, sizeof(c));
for (i=1; i<=2*n; i++)
{
scanf("%d", a+i);
if (flag[a[i]])
{
end[a[i]] = i;
}
else
{
begin[a[i]] = i;
flag[a[i]] = true;
}
update(i, 1);
}
for (i=1; i<=2*n; i++)
{
#if DEBUGE
printf("%d %d\n", begin[a[i]], end[a[i]]);
#else
if (!flag[a[i]])
{
continue;
}
//printf("%d\n", getsum(end[a[i]]-1));
ans += getsum(end[a[i]]-1);
flag[a[i]] = false;
update(begin[a[i]], -1);
update(end[a[i]], -1);
#endif
}
printf("%d\n", ans);
}
}