Codeforces Round #442 (Div. 2)
Problem A 水题 水一水
1 #include<bits/stdc++.h> 2 using namespace std; 3 char b[5][10],a[105]; 4 int main() 5 { 6 strcpy(b[0],"Danil"); 7 strcpy(b[1],"Olya"); 8 strcpy(b[2],"Slava"); 9 strcpy(b[3],"Ann"); 10 strcpy(b[4],"Nikita"); 11 scanf("%s",a); 12 int cnt=0; 13 int len=strlen(a); 14 for(int i=0;i<len;i++) 15 { 16 for(int j=0;j<5;j++) 17 { 18 bool flag=false; 19 int l=strlen(b[j]); 20 for(int k=0;k<l && i+k<len;k++) 21 { 22 if(a[i+k]!=b[j][k]) break; 23 if(k==l-1) flag=true; 24 } 25 if(flag) cnt++; 26 if(cnt>1) 27 { 28 i=len; 29 break; 30 } 31 } 32 } 33 if(cnt==0 || cnt>1) puts("NO"); 34 else puts("YES"); 35 return 0; 36 }
Problem B
题目大意:给你一个由a,b组成的字符串,长度不超过5000,然后让你删除一些字符让它
满足前一段全部都是a,中间一段全部都是b,最后一段全部都是a这种形式。
思路:很容易想到求前缀和和后缀和,然后枚举分割点进行求最大长度,忘了只有一段
的情况WA了一次。 还有一种做法是用dp扫一遍数组就行了,dp[ i ][ j ],表示当前i这个
字符的状态为j ,状态为在第一段,第二段,第三段。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=5005; 4 int a[N],b[N],r_a[N],r_b[N]; 5 char s[N]; 6 int main() 7 { 8 scanf("%s",s+1); 9 int len=strlen(s+1); 10 for(int i=1;i<=len;i++) 11 { 12 a[i]=a[i-1]; 13 b[i]=b[i-1]; 14 if(s[i]=='a') a[i]++; 15 else b[i]++; 16 } 17 for(int i=len;i>=1;i--) 18 { 19 r_a[i]=r_a[i+1]; 20 r_b[i]-r_b[i+1]; 21 if(s[i+1]=='a') r_a[i]++; 22 else r_b[i+1]++; 23 } 24 int ans=0; 25 for(int i=0;i<=len;i++) 26 { 27 for(int j=i+1;j<=len;j++) 28 { 29 int cnt=0; 30 cnt+=a[i]; 31 cnt+=r_a[j]; 32 cnt+=b[j]-b[i]; 33 ans=max(ans,cnt); 34 } 35 } 36 ans=max(ans,a[len]); 37 ans=max(ans,b[len]); 38 printf("%d\n",ans); 39 return 0; 40 }
dp代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=5005; 4 char s[N]; 5 int dp[N][3]; 6 int main() 7 { 8 scanf("%s",s+1); 9 int len=strlen(s+1); 10 for(int i=1;i<=len;i++) 11 { 12 if(s[i]=='a') 13 { 14 dp[i][0]=dp[i-1][0]+1; 15 dp[i][2]=max(dp[i-1][2],dp[i-1][1])+1; 16 dp[i][1]=dp[i-1][1]; 17 } 18 else 19 { 20 dp[i][1]=max(dp[i-1][0],dp[i-1][1])+1; 21 dp[i][0]=dp[i-1][0]; 22 dp[i][2]=dp[i-1][2]; 23 } 24 } 25 int ans=max(dp[len][0],max(dp[len][1],dp[len][2])); 26 printf("%d\n",ans); 27 return 0; 28 }
Problem C
题目大意:有一个1*n的图,每个点上有无数个坦克,现在你要去炸坦克,被个坦克要炸两次
才会摧毁。一个点的坦克第一次被炸时会想两边移动,问你最少需要放几颗炸弹,和这些炸弹
的位置。
思路:感觉是个智商题,感觉我被碾压了,我原来想的是一路炸过去再一路炸回来,然后处理
一下边界情况,发现错了,看了数据找到了规律,先炸一次偶数,再炸一次奇数,最后再炸一次
偶数,后来想了想确实是最优的。。。。。。。。。。
#include<bits/stdc++.h> using namespace std; int n; int main() { vector<int> ans; scanf("%d",&n); for(int i=2;i<=n;i+=2) ans.push_back(i); for(int i=1;i<=n;i+=2) ans.push_back(i); for(int i=2;i<=n;i+=2) ans.push_back(i); int len=ans.size(); printf("%d\n",len); for(int i=0;i<len;i++) printf("%d ",ans[i]); puts(""); return 0; }
Problem D
题目大意:给你n*m的图和一个起点,一个终点,一个人站在起点,每次他能向上下左右一个方向
前进k步以内,问你最少要多少步到达终点。n,m,k<=1000
思路:我们可以很容易地想到直接一个bfs来求,但是k的值最大为1000,复杂度最坏能卡成n*m*k
所以我就想用图的链表形式写,每访问过一个点就将这个点上边的点和下面的点相连,左边的点和
右边的点相连,然后我们的复杂度就变成了n*m。
ps:这个指针写的我好难受。
#include<bits/stdc++.h> using namespace std; const int N=1005; struct node { char c; int row,col; node *l,*r,*x,*s; }w[N][N]; char ss[3],ww[N][N]; struct step { step(int a=0,int b=0,int c=0){ row=a; col=b; cnt=c;} int row,col,cnt; }; step cur; bool vis[N][N]; int n,m,k,x1,x2,y1,y2; queue<step>Q; void work(int i,int j) { if(w[i][j].l!=NULL && w[i][j].r!=NULL) { w[i][j].l->r=w[i][j].r; w[i][j].r->l=w[i][j].l; } else if(w[i][j].l!=NULL) w[i][j].l->r=NULL; else if(w[i][j].r!=NULL) w[i][j].r->l=NULL; if(w[i][j].s!=NULL && w[i][j].x!=NULL) { w[i][j].s->x=w[i][j].x; w[i][j].x->s=w[i][j].s; } else if(w[i][j].s!=NULL) w[i][j].s->x=NULL; else if(w[i][j].x!=NULL) w[i][j].x->s=NULL; } void dfs(int row,int col,int op) { if(row!=cur.row && col!=cur.col) work(row,col); if(op==1) { if(w[row][col].l!=NULL && cur.col-w[row][col].l->col<=k) { Q.push(step(w[row][col].l->row,w[row][col].l->col,cur.cnt+1)); work(w[row][col].l->row,w[row][col].l->col); dfs(w[row][col].l->row,w[row][col].l->col,1); w[row][col].l=NULL; } } else if(op==2) { if(w[row][col].r!=NULL && w[row][col].r->col-cur.col<=k) { Q.push(step(w[row][col].r->row,w[row][col].r->col,cur.cnt+1)); work(w[row][col].r->row,w[row][col].r->col); dfs(w[row][col].r->row,w[row][col].r->col,2); w[row][col].r=NULL; } } else if(op==3) { if(w[row][col].s!=NULL && cur.row-w[row][col].s->row<=k) { Q.push(step(w[row][col].s->row,w[row][col].s->col,cur.cnt+1)); work(w[row][col].s->row,w[row][col].s->col); dfs(w[row][col].s->row,w[row][col].s->col,3); w[row][col].s=NULL; } } else if(op==4) { if(w[row][col].x!=NULL && w[row][col].x->row-cur.row<=k) { Q.push(step(w[row][col].x->row,w[row][col].x->col,cur.cnt+1)); work(w[row][col].x->row,w[row][col].x->col); dfs(w[row][col].x->row,w[row][col].x->col,4); w[row][col].x=NULL; } } } int main() { cin>>n>>m>>k; for(int i=1;i<=n;i++) scanf("%s",ww[i]+1); for(int i=1;i<=n;i++) { for(int j=1;j<=m; j++) { w[i][j].c=ww[i][j]; w[i][j].row=i; w[i][j].col=j; } } scanf("%d%d%d%d",&x1,&y1,&x2,&y2); for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { if(i-1>0 && w[i-1][j].c!='#') w[i][j].s=&w[i-1][j]; else w[i][j].s=NULL; if(i+1<=n && w[i+1][j].c!='#') w[i][j].x=&w[i+1][j]; else w[i][j].x=NULL; if(j-1>0 && w[i][j-1].c!='#') w[i][j].l=&w[i][j-1]; else w[i][j].l=NULL; if(j+1<=m && w[i][j+1].c!='#') w[i][j].r=&w[i][j+1]; else w[i][j].r=NULL; } } work(x1,y1); Q.push(step(x1,y1,0)); while(!Q.empty()) { cur=Q.front(); Q.pop(); if(cur.row==x2 && cur.col==y2) { printf("%d\n",cur.cnt); return 0; } dfs(cur.row,cur.col,1); dfs(cur.row,cur.col,2); dfs(cur.row,cur.col,3); dfs(cur.row,cur.col,4); } puts("-1"); return 0; }
Problem E
题目大意:给你一棵以 1 为根节点的树,每个节点代表的值是1或者0,然后有q个有两种操作,
一种操作是询问一棵子树里1的个数,另一种操作是将一棵子树的值翻转。
思路:想了一会就想出来了,以前好像写过类似的题,用dfs序将每棵子树转换成一个区间,
然后就变成了 RMQ问题,用线段树就好了,push_down里面写搓了一次,不能直接将左子树
和右子树的lazy变成1,要让它们++ 再对2 取模。
1 #include<bits/stdc++.h> 2 #define lson l,m,rt<<1 3 #define rson m+1,r,rt<<1|1 4 using namespace std; 5 const int N=2*1e5+5; 6 int lazy[N<<2],seg[N<<2],n,s[N],e[N],tot,a[N],b[N]; 7 vector<int> E[N]; 8 void build(int l,int r,int rt) 9 { 10 if(l==r) 11 { 12 if(a[l]==1) seg[rt]=1; 13 return; 14 } 15 int m=(l+r)>>1; 16 build(lson); 17 build(rson); 18 seg[rt]=seg[rt<<1]+seg[rt<<1|1]; 19 } 20 void dfs(int v) 21 { 22 int len=E[v].size(); 23 s[v]=++tot; 24 for(int i=0;i<len;i++) 25 { 26 int to=E[v][i]; 27 dfs(to); 28 } 29 e[v]=tot; 30 } 31 void push_down(int rt,int l,int r) 32 { 33 if(!lazy[rt]) return; 34 lazy[rt]=0; 35 int m=(l+r)>>1; 36 seg[rt<<1]=m-l+1-seg[rt<<1]; 37 seg[rt<<1|1]=r-m-seg[rt<<1|1]; 38 lazy[rt<<1]++; lazy[rt<<1|1]++; 39 lazy[rt<<1]%=2; lazy[rt<<1|1]%=2; 40 } 41 void update(int L,int R,int l,int r,int rt) 42 { 43 if(l>=L && r<=R) 44 { 45 seg[rt]=r-l+1-seg[rt]; 46 lazy[rt]++; lazy[rt]%=2; 47 return; 48 } 49 int m=(l+r)>>1; 50 push_down(rt,l,r); 51 if(L<=m) update(L,R,lson); 52 if(R>m) update(L,R,rson); 53 seg[rt]=seg[rt<<1]+seg[rt<<1|1]; 54 } 55 int query(int L,int R,int l,int r,int rt) 56 { 57 if(l>=L && r<=R) return seg[rt]; 58 int m=(l+r)>>1; 59 push_down(rt,l,r); 60 int ans=0; 61 if(L<=m) ans+=query(L,R,lson); 62 if(R>m) ans+=query(L,R,rson); 63 return ans; 64 } 65 int main() 66 { 67 scanf("%d",&n); 68 for(int i=2;i<=n;i++) 69 { 70 int f; scanf("%d",&f); 71 E[f].push_back(i); 72 } 73 for(int i=1;i<=n;i++) scanf("%d",&b[i]); 74 dfs(1); 75 for(int i=1;i<=n;i++) if(b[i]) a[s[i]]=1; 76 build(1,n,1); 77 int q; scanf("%d",&q); 78 while(q--) 79 { 80 char ss[5]; 81 int g; 82 scanf("%s%d",ss,&g); 83 if(ss[0]=='g') printf("%d\n",query(s[g],e[g],1,n,1)); 84 else update(s[g],e[g],1,n,1); 85 } 86 return 0; 87 }