T1 Blue
一点都不简单,可是还是有很多巨佬$A$掉了。
对于每只蛤,都应该向它所能到达的最远地方跳,蛤都相同,若有一只蛤跳向最远,那可能就会有另一只蛤无法超过他从而跳向较近的位置。而假设起先那只蛤跳到了较近的位置,另一只蛤还会跳向更远的位置,此时两只蛤互相交换了位置,而但是效果等价。
贪心从前向后贪。
证明:
如果最右的蛤不往最远的石子跳,而是选择了一个较近的石子,那么必然会存在一个该蛤左边的蛤越过了它跳向其右边。因为每个蛤的能力是相同的,我们可以交换路线使得该贪心策略不变差。
接着用归纳法可以证明对于所有蛤该策略最优。
然后就简单了,$set$模拟也可以,队列也可以,注意队列中的元素代表的是有效蛤所在的位置。
$set$模拟注意set中要插入0和最大的L,以保证STL的空间的安全(如$--s.begin()$)。
STL中$lower_bound$是大于等于它的元素,$--$之后是小于,$upper_bound$是大于它的元素,$--$之后是小于等于。
小弟不才。
1 #include<cstdio> 2 #include<algorithm> 3 #include<set> 4 #define HZOI std; 5 using namespace HZOI; 6 int T,n,m,d,L,ans; 7 set<int> s; 8 inline int read(); 9 int main() 10 { 11 // freopen("blue.in","r",stdin); 12 // freopen("3.out","w",stdout); 13 T=read(); 14 // double t1=clock(); 15 while (T--) 16 { 17 ans=0; 18 s.clear(); 19 n=read(),m=read(),d=read(),L=read(); 20 for (int i=1; i<=n; ++i) 21 s.insert(read()); 22 s.insert(0),s.insert(L); 23 if (d==L) 24 { 25 puts("Excited"); 26 continue; 27 } 28 if (n==L-1) 29 { 30 if (d>=m) puts("Excited"); 31 else printf("%d ",d); 32 continue; 33 } 34 for (int i=1; i<=m; ++i) 35 { 36 int pos=0,flag=1; 37 int to; 38 // printf("i=%d======= ",i); 39 do 40 { 41 to=*--s.upper_bound(pos+d); 42 // printf("pos=%d to=%d ",pos,to); 43 if (to<=pos or to-pos>d) {flag=0;break;} 44 if (to>=L) {++ans;break;} 45 else pos=to,s.erase(to); 46 }while (pos); 47 if (!flag) break; 48 } 49 if (ans==m) puts("Excited"); 50 else printf("%d ",ans); 51 } 52 // double t2=clock(); 53 // printf("%.9lf ",t2-t1); 54 } 55 inline int read() 56 { 57 int nn=0; char cc=getchar(); 58 while (cc<'0' or cc>'9') cc=getchar(); 59 while (cc>='0' and cc<='9') nn=(nn<<3)+(nn<<1)+(cc^48),cc=getchar(); 60 return nn; 61 }
1 #include<cstdio> 2 #define HZOI std; 3 using namespace HZOI; 4 const int N=1e6+3; 5 int T,n,m,d,L,l,r; 6 int a[N],q[N<<1]; 7 inline int read(); 8 int main() 9 { 10 T=read(); 11 while (T--) 12 { 13 n=read(),m=read(),d=read(),L=read(); 14 for (int i=1; i<=n; ++i) 15 a[i]=read(); 16 l=r=0; 17 for (int i=1; i<=m; ++i) q[++r]=0; 18 for (int i=1; i<=n; ++i) 19 { 20 while ((l^r) and q[l+1]+d<a[i]) ++l; 21 ++l,q[++r]=a[i]; 22 } 23 while ((l^r) and q[l+1]+d<L) ++l; 24 if (r-l==m) puts("Excited"); 25 else printf("%d ",r-l); 26 } 27 } 28 inline int read() 29 { 30 int nn=0; char cc=getchar(); 31 while (cc<'0' or cc>'9') cc=getchar(); 32 while (cc>='0' and cc<='9') nn=(nn<<3)+(nn<<1)+(cc^48),cc=getchar(); 33 return nn; 34 }
T2 Weed
线段树,考验对线段树维护信息的理解。
我是按照学长的题解码的,学长写的很好,很明白了。
要是在网上搜这篇题解,会有“这不是一道板子题吗”的嘲讽。
具体,我先引用一下学长的课件:
•实际上,每个加数和删除的操作可以看作是入栈和弹栈操作,之后可以用线段树维护多个操作间的关系。线段树的下标是操作时间,由于我们想得到整个序列经过修改操作后的结果,因此线段树上维护四个信息:
s:区间内加数总和(仅考虑区间内部影响);
nd:当前区间向前删除数字的数量;
na:当前区间内“净”加的元素数。
sd:当前区间被右兄弟删除后的总和。 ※仅对左儿子维护此信息。
•我们通过维护以上四个标记,就可以得到答案(root->s)。现在我们考虑如何维护信息。首先,在建树或修改时,只需要将叶子节点的前三个标记维护好即可;在递归返回时,再计算最后一个。如果左儿子不够右儿子删,那么非常简单,直接利用这几个标记计算即可,l->sd=0。
比较麻烦的是左儿子不被删光的情况。我们先实现一个函数cal(x),利用sd标记计算在当前区间中删去x个元素后的和。考虑cal(x)的实现(当前节点为o):
• 1.若r->na>x,那么返回l->sd+r->cal(x)。
• 2.若r->na<x,那么右儿子不够删,返回l->cal(x-r->na+r->nd)
• ※这里非常重要,一定要再删掉右儿子要删的
• 3.若r->na==x,直接返回l->sd。
有了这个函数,我们就可以非常方便地计算左儿子的sd,维护其他标记了,不再赘述。• 由于这个奇怪的函数在每层节点都会调用,而一共有O(logn)层节点,所以线段树操作的时间复杂度变为O(log 2 n),总时间复杂度也比常规的线段树多一个log。
• 难点主要在于使用额外的函数维护信息,并正确的讨论各种情况。
• 考试时一定要想清楚,时间复杂度是靠“链状”延伸的维护函数保障的,如果不小心写成了两边都下去,就变成O(n 2 )了。
好的搬完了溜了。
我们来分析一下这个题解。
主要是在于信息的理解和$cal$函数的实现。
$na$表示“净”增加,求出来的是当前区间受到自己区间内部的影响而得出来的净增加,$nd$表示“净”减少,求出来的是当前区间受到自己区间内部影响的净减少,所以,$na$可以被作用与之后的区间,$nd$可以作用于之前的区间,这就是他们的关系,由此合并信息的时候也就不难合并了,要想好区间本身、区间与区间的关系。
$s$表示总数,$sd$表示左儿子受到右儿子影响后得到的总数,所以s只考虑内部贡献,而$sd$考虑的是一区间对另一区间的贡献。
主要难点在于区间对区间的贡献,影响是相对于区间而言的。
$cal$函数的具体实现方式,师兄的博客中也已经很清楚了,不再多说。
$cal$函数的实现很巧妙,有效的作出了线段树本身没有的操作。
具体实现代码中展示。
小弟不才。
1 #include<cstdio> 2 #define HZOI std; 3 using namespace HZOI; 4 const int N=2e6+3; 5 struct Tree{ 6 int l,r,na,nd,sm,smd; 7 }tr[N<<2]; 8 int m,Q,t; 9 void Build(int ,int ,int ); 10 void Change(int ,int ,int ,int ); 11 int Cal(int ,int ); 12 inline int read(); 13 int main() 14 { 15 m=read(),Q=read(); 16 Build (1,1,m); 17 for (int i=1,x,y; i<=m; ++i) 18 x=read(),y=read(),Change(1,i,x,y); 19 for (int i=1,x,y,z; i<=Q; ++i) 20 { 21 x=read(),y=read(),z=read(); 22 Change(1,x,y,z); 23 printf("%d ",tr[1].sm); 24 } 25 return 0; 26 } 27 int Cal(int k,int x) 28 { 29 if (tr[k].l==tr[k].r) return x>=tr[k].na?0:tr[k].sm; 30 if (tr[k<<1|1].na==x) return tr[k<<1].smd; 31 else if (tr[k<<1|1].na<x) return Cal(k<<1,x-tr[k<<1|1].na+tr[k<<1|1].nd); 32 else if (tr[k<<1|1].na>x) return Cal(k<<1|1,x)+tr[k<<1].smd; 33 } 34 void Change(int k,int pos,int opt,int weight) 35 { 36 if (tr[k].l==tr[k].r) 37 { 38 if (opt) tr[k].nd=weight,tr[k].sm=tr[k].na=0; 39 else tr[k].na=1,tr[k].sm=weight,tr[k].nd=0; 40 return ; 41 } 42 int mid=tr[k].l+tr[k].r>>1; 43 if (pos<=mid) Change(k<<1,pos,opt,weight); 44 else Change(k<<1|1,pos,opt,weight); 45 tr[k].nd=tr[k<<1].nd+((tr[k<<1|1].nd-tr[k<<1].na)>0?(tr[k<<1|1].nd-tr[k<<1].na):0); 46 tr[k].na=tr[k<<1|1].na+((tr[k<<1].na-tr[k<<1|1].nd)>0?(tr[k<<1].na-tr[k<<1|1].nd):0); 47 if (tr[k<<1].l==tr[k<<1].r) 48 { 49 if (tr[k<<1|1].nd>=1) tr[k<<1].smd=0; 50 else tr[k<<1].smd=tr[k<<1].sm; 51 } 52 else 53 { 54 if (tr[k<<1|1].nd>=tr[k<<1].na) tr[k<<1].smd=0; 55 else tr[k<<1].smd=Cal(k<<1,tr[k<<1|1].nd); 56 } 57 tr[k].sm=tr[k<<1].smd+tr[k<<1|1].sm; 58 } 59 void Build(int k,int l,int r) 60 { 61 tr[k].l=l,tr[k].r=r; 62 if (l==r) return ; 63 int mid=l+r>>1; 64 Build(k<<1,l,mid); 65 Build (k<<1|1,mid+1,r); 66 } 67 inline int read() 68 { 69 int nn=0; char cc=getchar(); 70 while (cc<'0' or cc>'9') cc=getchar(); 71 while (cc>='0' and cc<='9') nn=(nn<<3)+(nn<<1)+(cc^48),cc=getchar(); 72 return nn; 73 }
T3 Drink
暴力可过,不明原因,循环展开。
小弟不才。
1 #include<cstdio> 2 #define HZOI std; 3 using namespace HZOI; 4 int n,m,Q,g,h; 5 char a[2003][2003],cc1,cc2,cc3,cc4; 6 int main() 7 { 8 scanf("%d%d%d",&n,&m,&Q); 9 for (int i=1; i<=n; ++i) 10 for (int j=1; j<=m; ++j) 11 { 12 a[i][j]=getchar(); 13 while (a[i][j]<'0' or a[i][j]>'9') a[i][j]=getchar(); 14 } 15 for (int q=1,x,y,z; q<=Q; ++q) 16 { 17 scanf("%d%d%d",&x,&y,&z); 18 for (int k=z; k>0; k-=2) 19 { 20 for (int i=0; i<k-1; ++i) 21 { 22 int tx1=x,ty1=y+i; 23 int tx2=x+i,ty2=y+k-1; 24 int tx3=x+k-1,ty3=y+k-1-i; 25 int tx4=x+k-1-i,ty4=y; 26 cc1=a[tx1][ty1]; 27 cc2=a[tx2][ty2]; 28 cc3=a[tx3][ty3]; 29 cc4=a[tx4][ty4]; 30 a[tx4][ty4]=cc3; 31 a[tx3][ty3]=cc2; 32 a[tx2][ty2]=cc1; 33 a[tx1][ty1]=cc4; 34 } 35 ++x,++y; 36 } 37 } 38 for (int i=1; i<=n; ++i) 39 { 40 for (int j=1; j<=m; ++j) 41 putchar(a[i][j]),printf(" "); 42 puts(""); 43 } 44 return 0; 45 }