两道树状数组题。
推荐一篇介绍树状数组比较好的博客: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+,很是无语~~