两道树状数组题。
推荐一篇介绍树状数组比较好的博客:http://www.cnblogs.com/yykkciwei/archive/2009/05/08/1452889.html
hdu 4000 Fruit Ninja
题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=4000
思路:对每个位置处理,考虑后面有多少比他大的数,则该位置上的数与后面两个大数可构成x*(x-1)/2种,再把所有的i<j<k && a[i]<a[j]<a[k]除去。
code:
# include<stdio.h>
# include<string.h>
# define Mod 100000007
int count[100005],n;
__int64 ans;
void insert(int i)
{
while(i<=n)
{
count[i]++;
i+= i&(-i);
}
}
int query(int i)
{
int num=0;
while(i>0)
{
num+=count[i];
i-=i&(-i);
}
return num;
}
int main()
{
int i,ncase,t,a;
__int64 tmp1,tmp2;
scanf("%d",&ncase);
for(t=1;t<=ncase;t++)
{
scanf("%d",&n);
memset(count,0,sizeof(count));
ans=0;
for(i=1;i<=n;i++)
{
scanf("%d",&a);
insert(a);
tmp1=query(a-1);//扫描比a小的数
tmp2=n-a-(i-tmp1-1);//在a后面比a大的数
ans-=tmp1*tmp2;//除去i<j<k && a[i]<a[j]<a[k]的情况
if(tmp2>=2) ans+=tmp2*(tmp2-1)/2;
}
printf("Case #%d: %d\n",t,ans%Mod);
}
return 0;
}
hdu 4020 Ads Proposal
题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=4020
可以用模拟预处理,感觉时间复杂度也不是很高,虽然AC了但4000+ms,估计数据量特别大。
此题也是树状数组。先把所有的广告根据点击次数从大到小进行排序,然后每处理一条广告,判断该条广告是这个人的第几天广告,然后把该条广告的长度作为增量增加到一个数组上!
code:
# include<stdio.h>
# include<string.h>
# include<stdlib.h>
# define M 500005
__int64 sum[M];
int m,visit[100005];
struct node{
int id,c,len;
}s[M];
int Lowbit(int i)
{
return i&(-i);
}
void puls(int i,int num)
{
while(i<=m)
{
sum[i]+=num;
i+=Lowbit(i);
}
}
__int64 getsum(int i)
{
__int64 ans=0;
while(i>0)
{
ans+=sum[i];
i-=Lowbit(i);
}
return ans;
}
int cmp(const void *a,const void *b)
{
struct node *c=(struct node *)a;
struct node *d=(struct node *)b;
return d->c - c->c;
}
int main()
{
int i,n,Q,ncase,t,k;
scanf("%d",&ncase);
for(t=1;t<=ncase;t++)
{
scanf("%d%d%d",&n,&m,&Q);
for(i=1;i<=m;i++)
scanf("%d%d%d",&s[i].id,&s[i].c,&s[i].len);
qsort(s+1,m,sizeof(s[1]),cmp);
memset(visit,0,sizeof(visit));
memset(sum,0,sizeof(sum));
for(i=1;i<=m;i++)
{
visit[s[i].id]++;
puls(visit[s[i].id],s[i].len);
}
printf("Case #%d:\n",t);
while(Q--)
{
scanf("%d",&k);
if(k>m) k=m;
printf("%I64d\n",getsum(k));
}
}
return 0;
}
感觉写的也没错啊。。不过交了之后仍然4000ms+,很是无语~~