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.好像很都存在两个相对大小变量的题,按其中一个变量排序后,题目都会变得很愉悦~
代码如下:
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<string>
#include<iostream>
#define INF 9999999
#define LL long long
using namespace std;
struct Point{
int x;
long long v;
}a[];
bool cmp(const Point&X,const Point&Y){
return X.v<Y.v;
}
int Min=INF,Max=-INF;
int L,R,o,n;
long long sum[],num[];
long long now,ans;
long long query(int root,int l,int r){
if(!num[root]) return ;
if(L<=l&&r<=R)
return sum[root]-num[root]*now;
int mid=(l+r)>>;
long long t=;
if(mid>=L) t+=query(root<< ,l ,mid);
if(mid<R) t+=query(root<<|,mid+,r);
return t;
}
void insert(int root,int l,int r,int p){
sum[root]+=p;
num[root]++;
if(l==r) return ;
int mid=(l+r)>>;
if(mid>=p) insert(root<<,l,mid,p);
else insert(root<<|,mid+,r,p);
}
int main(){
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%lld%d",&a[i].v,&a[i].x);
Min=min(a[i].x,Min);
Max=max(a[i].x,Max);
}
sort(a+,a++n,cmp);
LL T=;
for(int i=;i<=n;i++){
now=a[i].x;
L=a[i].x ; R=Max;
ans+=a[i].v*query(,Min,Max);
L=Min ; R=a[i].x;
ans-=a[i].v*query(,Min,Max);
insert(,Min,Max,a[i].x);
}
printf("%lld",ans);
}
-----------------------------------------------------------------------------------
奶牛抗议
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中显然有许多无用间隔,离散之,
代码如下:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<iostream>
#define INF 999999999999
#define LL long long
#define N 1000002
#define key 1000000009
//using namespace std ;
struct Cow{
LL sum;
int p;
}a[N];
bool cmp(const Cow &x,const Cow &y){
return x.sum<y.sum;
}
int L,R,P,n,p[N];
LL sum[N];
int lowbit(int x){
return x&(-x);
}
void update(int x,LL val){
while(x<=n){
sum[x]=(sum[x]+val)%key;
x+=lowbit(x);
}
}
LL cal(int x){
LL temp=;
while(x){
temp=(temp+sum[x])%key;
x-=lowbit(x);
}
return temp;
}
int main(){
scanf("%d",&n);
for(int i=;i<=n;i++){
LL val;
scanf("%I64d",&val);
a[i].sum=a[i-].sum+val;
a[i].p=i;
}
a[n+].sum=;
a[n+].p=n+;
std :: sort(a+,a+n+,cmp);
int t=;
for(int i=;i<=n+;i++){
if(i==||a[i].sum!=a[i-].sum) ++t;
p[a[i].p]=t;
}
update(p[n+],);
LL temp=;
for(int i=;i<=n;i++){
temp=cal(p[i]);
update(p[i],temp);
}
printf("%I64d",temp);
}
最新文章
- Android File存储
- Flink - state管理
- WEB语言转义总结
- windows 访问 ubuntu虚拟机 django服务器 失败
- Java线程同步的方式
- HDU 5284 wyh2000 and a string problem(字符串,水)
- Fragment生命周期详解
- PHP学习笔记 - 进阶篇(7)
- Android之开发常用颜色
- The mmap module
- 基于CentOS 5.4搭建nginx+php+spawn-fcgi+mysql高性能php平台
- WPF Media 简单的播放器
- 【POJ3461】Oulipo
- vue stylus 格式化问题
- Generative Adversarial Nets[BEGAN]
- spring boot 集成disconf
- WPF中控件的显示与隐藏
- UE.getEditor(&#39;editor&#39;)
- Beta阶段DAY1
- MyBatis—mybatis-config.xml配置介绍