usaco 奶牛集会 && 奶牛抗议

奶牛集会

Description

约翰家的N头奶牛每年都会参加“哞哞大会” 。哞哞大会是世界奶牛界的盛事。集会上 的活动很多,比如堆干草,跨栅栏,摸牛仔的屁股等等。当然,哞哞大叫肯定也包括在内。 奶牛们的叫声很大,很多奶牛在参加多年活动之后,实际上已经失去了一部分的听力。

奶牛们已经站在了一条直线上,i号奶牛的坐标为Xi,她只能听到大于Vi的声音。每头奶 牛的位置坐标都是唯一的。

如果i号和j号奶牛想对话,则他们使用的音量为max {Vi, Vj} × |Xi −Xj|

N头奶牛可以组合成N(N − 1)/2对奶牛,假设每对奶牛都使用最小的音量在对话,请计 算所有奶牛产生的总音量是多少。

Input Format

第一行:单个整数:N,1 ≤ N ≤ 20000

第二行到第N + 1行:每行有两个用空格分开的整数,Vi和Xi,1 ≤ Vi ≤ 20000, 1 ≤ Xi ≤ 20000

Output Format

第一行:单个整数,表示最小音量之和

----------------------------------------------------------

正解=线段树(其实用树状数组也可以)

注意到max{vi,vj}中,显然只有大的才有贡献

将 vi 从小到大排序一一进树:

    设当前做到 i  

    先统计当前线段树中比xi大的个数num1及和sum1,ans+=vi*(sum1-num1*xi)

    再统计当前线段树中比xi小的个数num2及和sum2,ans+=vi*(num2*xi-sum2)

    将 xi 插入线段树

Ps.好像很都存在两个相对大小变量的题,按其中一个变量排序后,题目都会变得很愉悦~

代码如下:

 1 #include<cstring>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<string>
 5 #include<iostream>
 6 #define INF 9999999
 7 #define LL long long
 8 using namespace std;
 9 struct Point{
10     int x;
11     long long v;
12 }a[20001];
13 bool cmp(const Point&X,const Point&Y){
14     return X.v<Y.v;
15 }
16 int Min=INF,Max=-INF;
17 int L,R,o,n;
18 long long sum[200000],num[200000];
19 long long now,ans;
20 long long query(int root,int l,int r){
21     if(!num[root]) return 0;
22     if(L<=l&&r<=R) 
23       return  sum[root]-num[root]*now;
24     int mid=(l+r)>>1;
25     long long t=0;
26     if(mid>=L) t+=query(root<<1  ,l  ,mid);
27     if(mid<R)  t+=query(root<<1|1,mid+1,r);
28     return t;
29 }
30 void insert(int root,int l,int r,int p){
31     sum[root]+=p;
32     num[root]++;
33     if(l==r)  return ;
34     int mid=(l+r)>>1;
35     if(mid>=p) insert(root<<1,l,mid,p);
36     else insert(root<<1|1,mid+1,r,p);
37 }
38 int main(){
39     scanf("%d",&n);
40     for(int i=1;i<=n;i++){
41       scanf("%lld%d",&a[i].v,&a[i].x);
42       Min=min(a[i].x,Min);
43       Max=max(a[i].x,Max);
44     }
45     sort(a+1,a+1+n,cmp);
46     LL T=0;
47     for(int i=1;i<=n;i++){
48         now=a[i].x;
49         L=a[i].x ; R=Max;
50         ans+=a[i].v*query(1,Min,Max);
51         L=Min ;      R=a[i].x;
52         ans-=a[i].v*query(1,Min,Max);
53         insert(1,Min,Max,a[i].x);
54     }
55     printf("%lld",ans);
56 }
View Code

 

 -----------------------------------------------------------------------------------

奶牛抗议 

Description

 

约翰家的N头奶牛聚集在一起,排成一列,正在进行一项抗议活动。第i头奶牛的理智度 为Ai,Ai可能是负数。约翰希望奶牛在抗议时保持理性,为此,他打算将所有的奶牛隔离成 若干个小组,每个小组内的奶牛的理智度总和都要大于零。由于奶牛是按直线排列的,所以 一个小组内的奶牛位置必须是连续的。

请帮助约翰计算一下,存在多少种不同的分组的方案。由于答案可能很大,只要输出答 案除以1,000,000,009的余数即可。

 

Input Format

 

第一行:单个整数:N,1 ≤ N ≤ 10^6

第二行到N + 1行:在第i + 1行有一个整数:Ai,表示第i头奶牛的理智度,−10^5 ≤ Ai ≤ 10^5

 

Output Format

 

第一行:单个整数,表示分组方案数除以1,000,000,009的余数

--------------------------------------------------------------------------------------------------

正解=离散化+树状数组,

和上一题有异曲同工之妙~

设f[i] 为到第 i 只奶牛有几种分组,

设sum[i]为奶牛的前缀和

显然 f[i]= ∑f[j](sum[i]-sum[j]>=0)

 

注意到条件可以转化为 sum[i]>=sum[j],

f[i]=在 i 前 sum[j] 小于 sum[j] 的 f[i] 的和

可以用树状数组求和(由于只有单点修改,用树状数组比较方便 >_<)

sum中显然有许多无用间隔,离散之,

代码如下:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<string>
 5 #include<cmath>
 6 #include<queue>
 7 #include<iostream>
 8 #define INF 999999999999
 9 #define LL long long
10 #define N 1000002
11 #define key 1000000009
12 //using namespace std ;
13 struct Cow{
14     LL sum;
15     int p;
16 }a[N];
17 bool cmp(const Cow &x,const Cow &y){
18     return x.sum<y.sum;
19 }
20 int L,R,P,n,p[N];
21 LL sum[N];
22 int lowbit(int x){
23     return x&(-x);
24 }
25 void update(int x,LL val){
26     while(x<=n){
27         sum[x]=(sum[x]+val)%key;
28         x+=lowbit(x);
29     }
30 }
31 LL cal(int x){
32     LL temp=0;
33     while(x){
34         temp=(temp+sum[x])%key;
35         x-=lowbit(x);
36     }
37     return temp;
38 }
39 int main(){
40     scanf("%d",&n);
41     for(int i=1;i<=n;i++){
42         LL val;
43         scanf("%I64d",&val);
44         a[i].sum=a[i-1].sum+val;
45         a[i].p=i;
46     }
47     a[n+1].sum=0;
48     a[n+1].p=n+1;
49     std :: sort(a+1,a+n+2,cmp);
50     int t=0;
51     for(int i=1;i<=n+1;i++){
52         if(i==1||a[i].sum!=a[i-1].sum) ++t;
53         p[a[i].p]=t;
54     }
55     update(p[n+1],1);
56     LL temp=0;
57     for(int i=1;i<=n;i++){
58         temp=cal(p[i]);
59         update(p[i],temp);
60     }
61     printf("%I64d",temp);
62 }
View Code

 

posted @ 2013-10-22 10:12  Mr. Black  阅读(1306)  评论(0编辑  收藏  举报