T1:Blue
贪心就完了,显然一只蛤尽量往远跳是最优的,用每次跳跃跨过的石头数更新答案就完了。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<cstdlib> 7 using namespace std; 8 const int MAXN=1000005,INF=0x3f3f3f3f; 9 int T; 10 int n,m,d,L,a[MAXN],ans; 11 inline int R() { 12 int a=0;char c=getchar(); 13 while(c>'9'||c<'0')c=getchar(); 14 while(c>='0'&&c<='9')a=a*10+c-'0',c=getchar(); 15 return a; 16 } 17 bool flag; 18 int main() { 19 T=R(); 20 while(T--) { 21 n=R();m=R();d=R();L=R(); 22 for(int i=1;i<=n;i++) a[i]=R(); 23 a[0]=0;a[n+1]=L;ans=m; 24 int now=0; 25 for(int i=0;i<=n+1;i++) { 26 while(now!=n+1&&a[now+1]-a[i]<=d) ++now; 27 if(i==now) { 28 printf("0 "),flag=1; 29 break; 30 } 31 if(now==n+1) break; 32 ans=min(ans,now-i); 33 } 34 if(!flag) { 35 if(ans==m) printf("Excited "); 36 else printf("%d ",ans); 37 } 38 flag=0; 39 } 40 return 0; 41 }
T2:Weed
用线段树维护操作序列,难点在pushup怎么写,考虑每个节点维护三个信息:
还能删几层,还剩几层,剩下的高度和
前两个信息可以通过简单的判断$O(1)$计算
第三个信息可以向下递归计算,具体实现看代码的ask函数
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #include<algorithm> #include<queue> #include<vector> #include<cstdlib> using namespace std; const int MAXN=300005; int m,q; struct opt { int k,v; }o[MAXN]; struct node { int l,r,sum,c,e; }tr[MAXN*4]; int ask(int p,int e) { if(e==tr[p<<1|1].c) return tr[p].sum-tr[p<<1|1].sum; if(e<tr[p<<1|1].c) return tr[p].sum-tr[p<<1|1].sum+ask(p<<1|1,e); return ask(p<<1,e-tr[p<<1|1].c+tr[p<<1|1].e); } void up(int p) { if(tr[p<<1|1].e>=tr[p<<1].c) { tr[p].e=tr[p<<1].e+tr[p<<1|1].e-tr[p<<1].c; tr[p].c=tr[p<<1|1].c; tr[p].sum=tr[p<<1|1].sum; } else if(!tr[p<<1|1].e) { tr[p].c=tr[p<<1].c+tr[p<<1|1].c; tr[p].sum=tr[p<<1].sum+tr[p<<1|1].sum; tr[p].e=tr[p<<1].e; } else { tr[p].e=tr[p<<1].e; tr[p].c=tr[p<<1|1].c+tr[p<<1].c-tr[p<<1|1].e; tr[p].sum=tr[p<<1|1].sum+ask(p<<1,tr[p<<1|1].e); } } void build(int p,int l,int r) { tr[p].l=l,tr[p].r=r; if(l==r) { tr[p].sum=o[l].k?0:o[l].v; tr[p].c=o[l].k?0:1; tr[p].e=o[l].k?o[l].v:0; return; } int mid=(l+r)>>1; build(p<<1,l,mid); build(p<<1|1,mid+1,r); up(p); } void change(int p,int x,int k,int c) { if(tr[p].l==tr[p].r) { tr[p].sum=k?0:c; tr[p].c=k?0:1; tr[p].e=k?c:0; return; } int mid=(tr[p].l+tr[p].r)>>1; if(x<=mid) change(p<<1,x,k,c); else change(p<<1|1,x,k,c); up(p); } int main() { scanf("%d%d",&m,&q); for(int i=1;i<=m;i++) scanf("%d%d",&o[i].k,&o[i].v); build(1,1,m); for(int i=1,aa,bb,cc;i<=q;i++) { scanf("%d%d%d",&aa,&bb,&cc); change(1,aa,bb,cc); printf("%d ",tr[1].sum); } return 0; }
ps:一道相似的题——楼房重建
T3:Drink
链表神题
对于每个点(可以看做一个人),规定一个正方向(面朝哪边)
并记录在这个方向下该点的前后左右分别是那些点
(以这个人的视角看他的前后左右分别是谁)
对于一次修改来说,只需要修改正方形边界上人的信息
注意,不需要也不能记录每个人的方向,因为这样会使修改的复杂度降至$O(n^2)$
只能记录某一个人(比如左上角)的方向和编号
再用前后左右的信息推出其他人的方向
1 #include<cmath> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstring> 5 #include<iostream> 6 #include<cstdlib> 7 #include<queue> 8 #include<vector> 9 using namespace std; 10 const int MAXN=2005; 11 int n,m,q,s[MAXN][MAXN]; 12 /* 13 0 14 3 x 1 15 2 16 */ 17 struct Point { 18 int id; 19 Point() {id=0;} 20 int x() { 21 return (id-1)/m+1; 22 } 23 int y() { 24 return (id-1)%m+1; 25 } 26 }fp,tmp[8][MAXN]; 27 int fd,tmpd[8][MAXN]; 28 bool operator == (const Point &aa,const Point &bb) { 29 return aa.id==bb.id; 30 } 31 Point New(int _x,int _y) { 32 Point ret; 33 ret.id=(_x-1)*m+_y; 34 return ret; 35 } 36 struct Node { 37 Point p[4]; 38 }a[MAXN][MAXN]; 39 inline int my_d(int d,int opt) { 40 return (opt-d+4)%4; 41 } 42 Point get_p(Point p,int d,int opt) { 43 //面向d的点p的opt方向的点 44 return a[p.x()][p.y()].p[my_d(d,opt)]; 45 } 46 int get_d(Point lp,Point p,int d,int opt) { 47 //面向d的点lp的opt方向的点p的方向 48 int topt=(opt+2)%4; 49 for(int i=0;i<4;i++) 50 if(get_p(p,i,topt)==lp) return i; 51 return -1; 52 } 53 void move(Point &p,int &d,int opt) { 54 Point tp=p; 55 p=get_p(p,d,opt); 56 d=get_d(tp,p,d,opt); 57 } 58 void modify(Point p,int d,Point c) { 59 //将p点的d方向上的点改为c 60 a[p.x()][p.y()].p[d]=c; 61 } 62 void change(int x,int y,int c) { 63 Point np=fp; 64 int nd=fd; 65 for(int i=1;i<x;i++) move(np,nd,2); 66 for(int i=1;i<y;i++) move(np,nd,1); 67 for(int i=1;i<=c;move(np,nd,1),++i) { 68 tmp[0][i]=np,tmp[4][i]=get_p(np,nd,0); 69 tmpd[0][i]=nd,tmpd[4][i]=get_d(np,tmp[4][i],nd,0); 70 } 71 move(np,nd,3); 72 for(int i=1;i<=c;move(np,nd,2),++i) { 73 tmp[1][i]=np,tmp[5][i]=get_p(np,nd,1); 74 tmpd[1][i]=nd,tmpd[5][i]=get_d(np,tmp[5][i],nd,1); 75 } 76 move(np,nd,0); 77 for(int i=1;i<=c;move(np,nd,3),++i) { 78 tmp[2][i]=np,tmp[6][i]=get_p(np,nd,2); 79 tmpd[2][i]=nd,tmpd[6][i]=get_d(np,tmp[6][i],nd,2); 80 } 81 move(np,nd,1); 82 if(x==1&&y==1) fp=np,fd=(nd+1)%4; 83 for(int i=1;i<=c;move(np,nd,0),++i) { 84 tmp[3][i]=np,tmp[7][i]=get_p(np,nd,3); 85 tmpd[3][i]=nd,tmpd[7][i]=get_d(np,tmp[7][i],nd,3); 86 } 87 for(int i=0;i<4;i++) 88 for(int j=1;j<=c;j++) 89 modify(tmp[i][j],my_d(tmpd[i][j],i),tmp[(i+1)%4+4][j]); 90 for(int i=4;i<8;i++) 91 for(int j=1;j<=c;j++) 92 modify(tmp[i][j],my_d(tmpd[i][j],(i+2)%4),tmp[(i-1)%4][j]); 93 } 94 void print() { 95 Point xp=fp,yp; 96 int xd=fd,yd; 97 for(int i=1;i<=n;move(xp,xd,2),++i) { 98 yp=xp;yd=xd; 99 for(int j=1;j<=m;move(yp,yd,1),++j) 100 printf("%d ",s[yp.x()][yp.y()]); 101 printf(" "); 102 } 103 } 104 int main() { 105 scanf("%d%d%d",&n,&m,&q); 106 for(int i=0;i<=n+1;i++) 107 for(int j=0;j<=m+1;j++) { 108 if(i!=0&&i!=n+1&&j!=0&&j!=m+1) 109 scanf("%d",&s[i][j]); 110 if(i!=0) a[i][j].p[0]=New(i-1,j); 111 if(i!=n+1) a[i][j].p[2]=New(i+1,j); 112 if(j!=0) a[i][j].p[3]=New(i,j-1); 113 if(j!=m+1) a[i][j].p[1]=New(i,j+1); 114 } 115 fp=New(1,1);fd=0; 116 for(int i=1,aa,bb,cc;i<=q;i++) { 117 scanf("%d%d%d",&aa,&bb,&cc); 118 change(aa,bb,cc); 119 } 120 print(); 121 return 0; 122 }