题目找链接。
题意:
非常清晰的题意,就不再多说了。
分析:
看到这一题,其实思路一下子就有了,先从最暴力的开始吧:我们每次找一个最大拆开,然后别的都加上,也就是直接模拟,首先,这样的正确性是没问题的,但是时间不行,所以我们,要想别的办法,只招最大,大家应该很容易想到优先队列,用优先队列直接模拟的复杂度还不如暴力,但我们可以优化:
想这样一个问题,这里有一些数字a1,a2,a3,a4,a5。。。你要使每一个数增加da(不是线段树。。。),我们要怎么操作呢,其实我们不用操作,我们找一个基数,让基数加da,然后查询每个元素的时候加上这个基数就好了,如果有不更新的,那么我们可以直接减去da(当然这样转换是因为不减的比减的少),然后我们就可以再次模拟了,但是,tle,tle,tle。。。其实nlogn的常熟小一点是可以过的,但是这里真的过不了,虽然vjudge时限是10000ms,但是这并不能让我们过掉,当然,手写堆我也试了,一样tle。
其实想到这里然后就好办了,我们的log其实很多都是浪费的复杂度,我们想一想,n比较小,我们对n个数进行排序之后,就不再排序了,开三个队列,分别存n个数,某一半的长度,另一半的长度,为什么不用排序了呢?虽然操作之后每个蚯蚓都会变长,但是我们加在了基数上,所有完全可以保证三个队列一直单增。于是这一题就好解决了。
然后,还有:如果用stl的话,队列里开long long会tle(stl常数有多大啊。。。)所以开int,当然,q才200,不会爆掉int。但是答案可不一定在int内。
最后就是代码。
#include <cstdio> #include <queue> #include <algorithm> using namespace std; const int maxn=1e5+10; int a[maxn]; queue<int> qu1; queue<int> qu2; queue<int> qu3; int Top(){ int qu11,qu22,qu33; if(qu1.empty()) qu11=-1e9; else qu11=qu1.front(); if(qu2.empty()) qu22=-1e9; else qu22=qu2.front(); if(qu3.empty()) qu33=-1e9; else qu33=qu3.front(); if(qu11>qu22&&qu11>qu33) return qu11; else if(qu22>qu33) return qu22; else return qu33; } void Pop(){ int qu11,qu22,qu33; if(qu1.empty()) qu11=-1e9; else qu11=qu1.front(); if(qu2.empty()) qu22=-1e9; else qu22=qu2.front(); if(qu3.empty()) qu33=-1e9; else qu33=qu3.front(); if(qu11>qu22&&qu11>qu33) qu1.pop(); else if(qu22>qu33) qu2.pop(); else qu3.pop(); } int main(){ int n,m; int q,u,v,t; // freopen("P2827_2(1).in","r",stdin); // freopen("ouou.out","w",stdout); scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t); long long Ha=0; for(int i=1;i<=n;i++) scanf("%d",&a[i]); sort(a+1,a+1+n); for(int i=n;i>=1;i--) qu1.push(a[i]); for(int i=1;i<=m;i++){ long long x=Top()+Ha; Pop(); int x1=u*x/v-Ha-q; int x2=x-u*x/v-Ha-q; qu2.push(x1); qu3.push(x2); if(i%t==0) printf("%lld ",x); Ha+=q; } printf(" "); for(int i=1;i<=m+n;i++){ if(i%t==0) printf("%lld ",Top()+Ha); Pop(); } return 0; }