【AC梦工厂】2017 Multi-University Training Contest 3 1003|| HDU6058
来源:互联网 发布:gre单词软件 编辑:程序博客网 时间:2024/06/07 13:59
先吐槽一下多校的难度
膜拜清华大神AK
传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6058
官方题解:
我们只要求出对于一个数x左边最近的k个比他大的和右边最近k个比他大的,扫一下就可以知道有几个区间的k大值是x.
我们考虑从小到大枚举x,每次维护一个链表,链表里只有>=x的数,那么往左往右找只要暴力跳k次,删除也是O(1)的。
时间复杂度:O(nk)
看!不!懂! 嗯,很容易理解嘛
题目大意:
给你一串1……n的排列需要你找出子串中第k小的元素的和,考虑到用链表去维护。求出对于一个数x左边最近的k个比他大的和右边最近k个比他大的,如果左边有m个比x大的就需要在右边找k-1-m个比x大的,统计这样的区间有多少个即可
(呵呵,说得简单),再用区间的数量乘上x即x对答案的贡献
上代码:
#include <bits/stdc++.h>using namespace std;map<int,int>ma; /**记录每个元素的位置(当然也可以用数组减少复杂度)**/struct Link{ int pre,next,num;}s[500005]; /**用数组去模拟链表**/int main(){// freopen("a.in","r",stdin);// freopen("a.out","w",stdout); int t; scanf("%d",&t); while(t--) { int n,k; memset(s,0,sizeof s); ma.clear(); long long sum=0; scanf("%d %d",&n,&k); for(int i=1;i<=n;i++) { scanf("%d",&s[i].num); s[i].pre=i-1; /**前后指针**/ s[i].next=i+1; /**当n==i的时候不要把s[i].next设为0,不然结果可能会出现负数**/ ma[s[i].num]=i; } long long ans=0; for(int i=1;i<=n;i++) { int l=ma[i],r=ma[i]; int cnt1=0,cnt2=0; int x[100]={0}; /**记录有多少个比x小的数字**/ for(int j=0;j<k;j++) /**往右找k个比x大的**/ { if(s[r].next!=0) { x[++cnt2]=s[r].next-r; r=s[r].next; }else break; } long long res=0; for(int j=l;j>0&&cnt1<k;j=s[j].pre) { cnt1++; if(k-cnt1-cnt2+1>0) continue; else res+=(j-s[j].pre)*x[k-cnt1+1]; } ans+=res*i; s[s[ma[i]].pre].next=s[ma[i]].next; /**这个地方调了3个小时的bug 这里是模拟删除链表的操作**/ s[s[ma[i]].next].pre=s[ma[i]].pre; /**怪自己的代码太丑**/ } printf("%lld\n",ans); } return 0;}
附上标程:反正我看不懂
#include<bits/stdc++.h>#define fi first#define se second#define rep(i,j,k) for(int i=(int)j;i<=(int)k;i++)#define per(i,j,k) for(int i=(int)j;i>=(int)k;i--)using namespace std;typedef long long LL;const int N=510000;inline void read(int &x){ x=0;char p=getchar(); while(!(p<='9'&&p>='0'))p=getchar(); while(p<='9'&&p>='0')x*=10,x+=p-48,p=getchar();}int n,k,a[N],pos[N],T;LL ans=0;int pre[N],np[N];int s[N],s0;int t[N],t0;void erase(int x){ int pp=pre[x]; int nn=np[x]; if(pre[x])np[pre[x]]=nn; if(np[x]<=n)pre[np[x]]=pp; pre[x]=np[x]=0;}void Main(){ read(n);read(k); rep(i,1,n){ read(a[i]); pos[a[i]]=i; } rep(i,1,n)pre[i]=np[i]=0; rep(i,1,n)pre[i]=i-1,np[i]=i+1; ans=0; rep(num,1,n-k+1){ int p=pos[num]; s0=t0=0; for(int d=p;d&&s0<=k+1;d=pre[d])s[++s0]=d; for(int d=p;d!=n+1&&t0<=k+1;d=np[d])t[++t0]=d; s[++s0]=0; t[++t0]=n+1; rep(i,1,s0-1){ if(k+1-i<=t0-1&&k+1-i>=1){ ans+=(t[k+1-i+1]-t[k+1-i])*1ll*(s[i]-s[i+1])*num; } } erase(p); } cout<<ans<<endl;}int main(){ read(T); while(T--)Main(); //cerr<<clock()<<endl; return 0;}
总结:
这次的高校打的不是太好,其中之一是题目的难度有点高,但是这不能成为借口,与平时补题比较少有关,确实补题的需要花不少的时间,但确实是有必要的,同时专题的训练也是不能少的继续加油
阅读全文
0 0
- 【AC梦工厂】2017 Multi-University Training Contest 3 1003|| HDU6058
- 2017 Multi-University Training Contest 3 1003/hdu6058
- #2017 Multi-University Training Contest 2 1003
- 2017 Multi-University Training Contest 4 1003
- 2017 Multi-University Training Contest 3
- 2017 Multi-University Training Contest 3 1005
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- 2017 Multi-University Training Contest
- linux安装mysql出现Could NOT find Curses (missing CURSES_LIBRARY CURSES_INCLUDE_PATH),提示解决方法
- nginx报错accept4() failed (23: Too many open files in system)
- 深度学习框架-浅析深度学习框架设计中的关键技术
- VS2013设置release版本可调试
- OpenCV对图像进行读取→显示→保存的源码!
- 【AC梦工厂】2017 Multi-University Training Contest 3 1003|| HDU6058
- 删除二叉查找树的节点
- 【ACM/ICPC训练】委派任务
- OSError: [Errno 1] Operation not permitted: '/tmp/pip-g3bg0s-uninstall/System/Library/Frameworks/Pyt
- 有两个双向循环链表A,B,知道其头指针为:pHeadA,pHeadB,请写一函数将两链表中data值相同的结点删除
- gradle项目链接mysql
- (多校02)hdu 6053 trickgcd (莫比乌斯函数)
- 如何调用chrome的桌面提示框
- 解决python针对hdfs上传和下载问题