Codeforces Round #619 (Div. 2)

A. Three Strings

题意:给三个长度相同的非空字符串abc,依次将c中的每个字符和a或者b中对应位置的字符进行交换,交换必须进行,问能否使得ab相同。

思路:对于每一个位置,如果三个字符都不相同,那一定不同,如果有两个相同且不是ab相同,则合法,否则不合法,如果三个字符都相同,那么合法。

 1 #include<bits/stdc++.h>
 2 #define LL long long
 3 #define dl double
 4 void rd(int &x){
 5  x=0;int f=1;char ch=getchar();
 6  while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
 7  while(ch<=‘9‘ && ch>=‘0‘)x=x*10+ch-‘0‘,ch=getchar();x*=f;
 8 }
 9 void lrd(LL &x){
10  x=0;int f=1;char ch=getchar();
11  while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
12  while(ch<=‘9‘ && ch>=‘0‘)x=x*10+ch-‘0‘,ch=getchar();x*=f;
13 }
14 const int INF=1e9;
15 const LL LINF=1e18;
16 const int inf=105;
17 using namespace std;
18 int T;
19 char a[inf],b[inf],c[inf];
20 bool check(int x){
21  if(a[x] == b[x])return a[x] != c[x];
22  if(a[x] == c[x] || b[x] == c[x])return 0;
23  return 1;
24 }
25 int main(){
26 // freopen("in.txt","r",stdin);
27  rd(T);
28  while(T--){
29   scanf("%s%s%s",a,b,c);
30   int n=strlen(a),flg=0;
31   for(int i=0;i<n;i++)
32    if(check(i))flg=1;
33   if(flg)printf("NO\n");
34   else printf("YES\n");
35  }
36  return 0;
37 }
38 /**/

B. Motarack‘s Birthday

题意:给一串数,一些位置没有数字,选择一个数填到所有空位上,使得相邻两数之差的绝对值的最大值最小。

思路:找出旁边有空位的数字中最大的和最小的,相加除二便可以得到使得空位和非空位之间差的绝对值的最大值最小的数,再统计一下非空位之间的贡献即可。

 1 #include<bits/stdc++.h>
 2 #define LL long long
 3 #define dl double
 4 void rd(int &x){
 5  x=0;int f=1;char ch=getchar();
 6  while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
 7  while(ch<=‘9‘ && ch>=‘0‘)x=x*10+ch-‘0‘,ch=getchar();x*=f;
 8 }
 9 void lrd(LL &x){
10  x=0;int f=1;char ch=getchar();
11  while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
12  while(ch<=‘9‘ && ch>=‘0‘)x=x*10+ch-‘0‘,ch=getchar();x*=f;
13 }
14 const int INF=1e9;
15 const LL LINF=1e18;
16 const int inf=1e5+10;
17 using namespace std;
18 int T,n;
19 int a[inf];
20 int mx,mn;
21 int main(){
22 /// freopen("in.txt","r",stdin);
23  rd(T);
24  while(T--){
25   rd(n);mx=0;mn=1e9+1;
26   for(int i=1;i<=n;i++)rd(a[i]);
27   for(int i=2;i<n;i++){
28    if(a[i] == -1)continue;
29    if(a[i-1] == -1 || a[i+1] == -1)mx=max(mx,a[i]),mn=min(mn,a[i]);
30   }
31   if(a[1] != -1 && a[2] == -1)mx=max(mx,a[1]),mn=min(mn,a[1]);
32   if(a[n] != -1 && a[n-1] == -1)mx=max(mx,a[n]),mn=min(mn,a[n]);
33   int ans1,ans2;ans2=(mn+mx)/2;
34   if(mx)ans1=max(mx-ans2,ans2-mn);else ans1=0;
35   for(int i=1;i<n;i++)if(a[i]!=-1 && a[i+1]!=-1)ans1=max(ans1,abs(a[i+1]-a[i]));
36   printf("%d %d\n",ans1,ans2);
37  }
38  return 0;
39 }
40 /**/

C. Ayoub‘s function

题意:定义f(s)表示01串s中包含至少一个1的连续子串的数目,求长度为n且有m个1的01串中f(s)的最大值。

思路:一共有n*(n-1)/2个子串,我们只需要求出一个1都不包括的子串的数目的最小值即可得到答案。可以发现只需要对连续的0串进行统计即可,答案为(l-1)*l/2,容易发现使得0串长度尽可能平均会使得答案最小,于是将其分为相等的m+1组,多出来的再一个一个分配给每一组,这样就得到了所有0串的长度,统计答案即可。

 1 #include<bits/stdc++.h>
 2 #define LL long long
 3 #define dl double
 4 void rd(int &x){
 5  x=0;int f=1;char ch=getchar();
 6  while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
 7  while(ch<=‘9‘ && ch>=‘0‘)x=x*10+ch-‘0‘,ch=getchar();x*=f;
 8 }
 9 void lrd(LL &x){
10  x=0;int f=1;char ch=getchar();
11  while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
12  while(ch<=‘9‘ && ch>=‘0‘)x=x*10+ch-‘0‘,ch=getchar();x*=f;
13 }
14 const int INF=1e9;
15 const LL LINF=1e18;
16 using namespace std;
17 int T;
18 int n,m;
19 int main(){
20 // freopen("in.txt","r",stdin);
21  rd(T);
22  while(T--){
23   rd(n),rd(m);
24   LL ans=0;
25   if(n == m)ans=1ll*n*(n+1)/2;
26   else if(!m)ans = 0;
27   else {
28    int u=(n-m)/(m+1),v=(n-m)%(m+1);
29    ans+=1ll*(m+1-v)*u*(u+1)/2;
30    ans+=1ll*v*(u+1)*(u+2)/2;
31    ans=1ll*n*(n+1)/2-ans;
32   }
33   printf("%lld\n",ans);
34  }
35  return 0;
36 }
37 /**/

D. Time to Run

题意:nm的格子,相邻格子之间有两条相反的单向路,从11开始沿着路走,可以在任意一个格子结束,每条路只能走一次,问能否走k条路,并输出方案。

思路:可以发现应该存在一个可以走的路的最大值,大胆猜测存在一种方式可以一次走完所有的路,构造可以发现,一直往右,然后下,一直往左,然后下,直到最后一行,然后上下左(右)重复到边界,往上走,继续重复即可一次走完所有的路。需要注意输出有要求,需要对一些步骤进行压缩,可以证明压缩后一定在3000以内。还需要注意处理单列的情况。

 1 #include<bits/stdc++.h>
 2 #define LL long long
 3 #define dl double
 4 void rd(int &x){
 5  x=0;int f=1;char ch=getchar();
 6  while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
 7  while(ch<=‘9‘ && ch>=‘0‘)x=x*10+ch-‘0‘,ch=getchar();x*=f;
 8 }
 9 void lrd(LL &x){
10  x=0;int f=1;char ch=getchar();
11  while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
12  while(ch<=‘9‘ && ch>=‘0‘)x=x*10+ch-‘0‘,ch=getchar();x*=f;
13 }
14 const int INF=1e9;
15 const LL LINF=1e18;
16 const int inf=3005;
17 using namespace std;
18 int n,m,k;
19 struct ghb{
20  int x;
21  char s[5];
22 }sta[inf];
23 int top;
24 int main(){
25 // freopen("in.txt","r",stdin);
26 // freopen("a.out","w",stdout);
27  rd(n);rd(m);rd(k);
28  if(4*n*m-2*n-2*m < k)printf("NO\n");
29  else {
30   printf("YES\n");
31   for(int i=1;i<=n;i++){
32    if(!k)break;
33    if(i & 1){
34     if(k <= m-1){sta[++top]=(ghb){k,"R"};k=0;break;}
35     k-=m-1;if(m-1)sta[++top]=(ghb){m-1,"R"};
36    }
37    else {
38     if(k <= m-1){sta[++top]=(ghb){k,"L"};k=0;break;}
39     k-=m-1;if(m-1)sta[++top]=(ghb){m-1,"L"};
40    }
41    if(k && i != n)sta[++top]=(ghb){1,"D"},k--;
42   }
43   for(int i=n;i>1;i--){
44    if(!k)break;
45    if(i & 1){
46     if(k <= (m-1)*3){
47      int tmp1=k/3,tmp2=k%3;
48      if(tmp1)sta[++top]=(ghb){tmp1,"UDL"};
49      if(tmp2 == 1)sta[++top]=(ghb){1,"U"};
50      if(tmp2 == 2)sta[++top]=(ghb){1,"UD"};
51      k=0;break;
52     }
53     if(m-1)sta[++top]=(ghb){m-1,"UDL"};k-=(m-1)*3;
54    }
55    else {
56     if(k <= (m-1)*3){
57      int tmp1=k/3,tmp2=k%3;
58      if(tmp1)sta[++top]=(ghb){tmp1,"UDR"};
59      if(tmp2 == 1)sta[++top]=(ghb){1,"U"};
60      if(tmp2 == 2)sta[++top]=(ghb){1,"UD"};
61      k=0;break;
62     }
63     if(m-1)sta[++top]=(ghb){m-1,"UDR"};k-=(m-1)*3;
64    }
65    if(k)k--,sta[++top]=(ghb){1,"U"};
66   }
67   if(k)sta[++top]=(ghb){k,"L"};
68   printf("%d\n",top);
69   for(int i=1;i<=top;i++)printf("%d %s\n",sta[i].x,sta[i].s);
70  }
71  return 0;
72 }
73 /**/

反思:遇到这种明显存在一个分界点的题,应该大胆猜想分界点是那个最特殊的点,nm格子这种题要单独考虑单行单列的情况。

E. Nanosoft

题意:定义一个logo是一个正方形,左上部分是红色,右上部分是绿色,左下部分是黄色,右下部分是蓝色,给一个nm的图,q次询问每次询问一个矩形区间内最大的logo有多大。

思路:首先可以考虑找出所有logo的位置,可以枚举中心,一层一层往外"剥",这样可以在nm时间复杂度内预处理出来,并可以得到他们的大小。考虑每次询问,试想我们从外往里一层一层剥,记录剥掉的层数k,再求出内部所有logo中心位置的logo大小的最大值,二者取较小值便可以得到一个小于等于答案的数,当内部的答案对应logo中心在最外层时便可以使得求出的值等于答案(当然其他的k也可能对应答案),区间最大值用二维st表解决即可,需要注意有很多边界的细节问题,此时时间复杂度已经合适,但有更优的解法,因为我们可以发现内部最大值随层数k的增加是递减的,同时得到最终答案的时候层数k一定是小于等于内部最大值的,所以应该找到尽可能大的k,所以可以二分答案找到满足k小于等于内部最大值的最大的k。需要注意上述说明中的小于或是大于之类的字眼都可能存在+1-1再比较大小的情况,因为我的代码中是取中心的左上角作为真正的中心,导致后面很多地方都需要+1-1之类的细节,具体情况画图即可得知。

 1 #include<bits/stdc++.h>
 2 #define LL long long
 3 #define dl double
 4 void rd(int &x){
 5  x=0;int f=1;char ch=getchar();
 6  while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
 7  while(ch<=‘9‘ && ch>=‘0‘)x=x*10+ch-‘0‘,ch=getchar();x*=f;
 8 }
 9 void lrd(LL &x){
10  x=0;int f=1;char ch=getchar();
11  while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
12  while(ch<=‘9‘ && ch>=‘0‘)x=x*10+ch-‘0‘,ch=getchar();x*=f;
13 }
14 const int INF=1e9;
15 const LL LINF=1e18;
16 const int N=505;
17 using namespace std;
18 int n,m,q;
19 char s[N][N];
20 int a[N][N];
21 int work(int x,int y,int z){
22  for(int i=0;i<z;i++)if(s[x][y+i] != ‘R‘ || s[x+2*z-1][y+i] != ‘Y‘ || s[x+i][y] != ‘R‘ || s[x+i][y+2*z-1] != ‘G‘)return z-1;
23  for(int i=z;i<2*z;i++)if(s[x][y+i] != ‘G‘ || s[x+2*z-1][y+i] != ‘B‘ || s[x+i][y] != ‘Y‘ || s[x+i][y+2*z-1] != ‘B‘)return z-1;
24  if(x > 1 && y > 1 && x+2*z <= n && y+2*z <= m)return work(x-1,y-1,z+1);else return z;
25 }
26 int st[N][N][9][9];
27 int f[N];
28 int get_ans(int x1,int y1,int x2,int y2){
29  if(x1 > x2 || y1 > y2)return 0;
30  int hx=f[x2-x1+1],hy=f[y2-y1+1];
31  return max(max(st[x1][y1][hx][hy],st[x1][y2-(1<<hy)+1][hx][hy]),max(st[x2-(1<<hx)+1][y1][hx][hy],st[x2-(1<<hx)+1][y2-(1<<hy)+1][hx][hy]));
32 }
33 int main(){
34 // freopen("in.txt","r",stdin);
35  rd(n);rd(m);rd(q);
36  for(int i=1;i<=n;i++)scanf("%s",s[i]+1);
37  for(int i=1;i<=n;i++)
38   for(int j=1;j<=m;j++)
39    a[i][j]=work(i,j,1);
40  f[0]=-1;for(int i=1;i<=max(n,m);i++)f[i]=f[i>>1]+1;
41  for(int i=0;(1<<i) <= n;i++)
42   for(int j=0;(1<<j) <= m;j++)
43    for(int x=1;x+(1<<i)-1 <= n;x++)
44     for(int y=1;y+(1<<j)-1 <= m;y++){
45      if(!i && !j)st[x][y][i][j]=a[x][y];
46      else if(!i)st[x][y][i][j]=max(st[x][y][i][j-1],st[x][y+(1<<j-1)][i][j-1]);
47      else st[x][y][i][j]=max(st[x][y][i-1][j],st[x+(1<<i-1)][y][i-1][j]);
48     }
49  for(int i=1;i<=q;i++){
50   int x1,y1,x2,y2;rd(x1);rd(y1);rd(x2);rd(y2);x2--;y2--;
51   if(x2 < x1 || y2 < y1){printf("0\n");continue;}
52   int l=0,r=min(x2-x1+1,y2-y1+1)/2;
53   while(l != r){
54    int mid=(l+r>>1)+1;
55    if(get_ans(x1+mid,y1+mid,x2-mid,y2-mid) >= mid+1)l=mid;
56    else r=mid-1;
57   }
58   int tmp=min(get_ans(x1+l,y1+l,x2-l,y2-l),l+1);
59   printf("%d\n",4*tmp*tmp);
60  }
61  return 0;
62 }
63 /**/

反思:一种解题的新思路吧,通过加上一种限定来使得当前答案可求,而这种限定甚至可以用二分优化。

F. Super Jaber

题意:nm格子,每个格子有颜色,颜色最多40种,每一步可以上下左右或者从当前格子跳到任意一个颜色相同的其他格子,q次询问两点之间的最短距离。

思路:如果不同色跳,那么横纵坐标差的绝对值加和即为答案,如果进行同色跳,不妨枚举用其中一次是哪一种同色跳,这就需要我们处理出每种颜色离一个点最近距离是多少,按颜色bfs,将所有该颜色点一次推入,用两种方式转移,需要注意同色跳操作在对于每种颜色预处理时每一种颜色至多一次(需要直接特判掉不然枚举的复杂度会很高)。

 1 #include<bits/stdc++.h>
 2 #define LL long long
 3 #define dl double
 4 void rd(int &x){
 5  x=0;int f=1;char ch=getchar();
 6  while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
 7  while(ch<=‘9‘ && ch>=‘0‘)x=x*10+ch-‘0‘,ch=getchar();x*=f;
 8 }
 9 void lrd(LL &x){
10  x=0;int f=1;char ch=getchar();
11  while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
12  while(ch<=‘9‘ && ch>=‘0‘)x=x*10+ch-‘0‘,ch=getchar();x*=f;
13 }
14 const int INF=1e9;
15 const LL LINF=1e18;
16 const int N=1005;
17 const int K=45;
18 using namespace std;
19 int n,m,k,q;
20 int a[N][N];
21 int dis[N][N][K];
22 struct Point{
23  int x,y;
24 };
25 queue<Point>S;
26 int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
27 vector<Point>T[K];
28 bool tag[K];
29 void get_dis(int x){
30  for(int i=0;i<T[x].size();i++)S.push(T[x][i]),dis[T[x][i].x][T[x][i].y][x]=0;
31  memset(tag,0,sizeof(tag));
32  while(!S.empty()){
33   Point u=S.front();S.pop();
34   for(int i=0;i<4;i++){
35    int tx=dx[i]+u.x,ty=dy[i]+u.y;
36    if(tx < 1 || tx > n || ty < 1 || ty > m || dis[tx][ty][x] != 0x3f3f3f3f)continue;
37    dis[tx][ty][x]=dis[u.x][u.y][x]+1;S.push((Point){tx,ty});
38   }
39   int col=a[u.x][u.y];
40   if(!tag[col]){
41    tag[col]=1;
42    for(int i=0;i<T[col].size();i++)
43     if(dis[T[col][i].x][T[col][i].y][x] == 0x3f3f3f3f)
44      dis[T[col][i].x][T[col][i].y][x]=dis[u.x][u.y][x]+1,S.push(T[col][i]);
45   }
46  }
47 }
48 int main(){
49 // freopen("in.txt","r",stdin);
50  rd(n);rd(m);rd(k);
51  for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)rd(a[i][j]),T[a[i][j]].push_back((Point){i,j});
52  memset(dis,0x3f,sizeof(dis));for(int i=1;i<=k;i++)get_dis(i);rd(q);
53  for(int i=1;i<=q;i++){
54   int r1,c1,r2,c2;rd(r1);rd(c1);rd(r2);rd(c2);
55   int ans=abs(r1-r2)+abs(c1-c2);
56   for(int j=1;j<=k;j++)ans=min(ans,dis[r1][c1][j]+dis[r2][c2][j]+1);
57   printf("%d\n",ans);
58  }
59  return 0;
60 }
61 /**/

反思:这使我回忆起了一个很常见好用的套路,即预处理部分,"求出距离当前点最近被标记点",这种可以通过一次性将所有被标记的点推入队列进行bfs得到。

原文地址:https://www.cnblogs.com/hyghb/p/12368997.html

时间: 2024-08-03 10:30:12

Codeforces Round #619 (Div. 2)的相关文章

Codeforces Round #619 (Div. 2) Ayoub&#39;s function

Ayoub thinks that he is a very smart person, so he created a function f(s)f(s) , where ss is a binary string (a string which contains only symbols "0" and "1"). The function f(s)f(s) is equal to the number of substrings in the string s

Codeforces Round #619 (Div. 2) 简要题解

A:只要每个位置都满足a[i] = c[i]或b[i] = c[i]即可. int main() { int t; scanf("%d", &t); while(t --) { char a[110], b[110], c[110]; scanf("%s%s%s", a, b, c); int n = strlen(a), tag = 1; for(int i = 0; i < n; i ++) { if(a[i] == c[i] || b[i] ==

Codeforces Round #619 (Div. 2)C(构造,容斥)

1 #define HAVE_STRUCT_TIMESPEC 2 #include<bits/stdc++.h> 3 using namespace std; 4 int main(){ 5 ios::sync_with_stdio(false); 6 cin.tie(NULL); 7 cout.tie(NULL); 8 int t; 9 cin>>t; 10 while(t--){ 11 long long n,m; 12 cin>>n>>m; 13 lo

Codeforces Round #428 (Div. 2)

Codeforces Round #428 (Div. 2) A    看懂题目意思就知道做了 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i

Codeforces Round #424 (Div. 2) D. Office Keys(dp)

题目链接:Codeforces Round #424 (Div. 2) D. Office Keys 题意: 在一条轴上有n个人,和m个钥匙,门在s位置. 现在每个人走单位距离需要单位时间. 每个钥匙只能被一个人拿. 求全部的人拿到钥匙并且走到门的最短时间. 题解: 显然没有交叉的情况,因为如果交叉的话可能不是最优解. 然后考虑dp[i][j]表示第i个人拿了第j把钥匙,然后 dp[i][j]=max(val(i,j),min(dp[i-1][i-1~j]))   val(i,j)表示第i个人拿

Codeforces Round #424 (Div. 2) C. Jury Marks(乱搞)

题目链接:Codeforces Round #424 (Div. 2) C. Jury Marks 题意: 给你一个有n个数序列,现在让你确定一个x,使得x通过挨着加这个序列的每一个数能出现所有给出的k个数. 问合法的x有多少个.题目保证这k个数完全不同. 题解: 显然,要将这n个数求一下前缀和,并且排一下序,这样,能出现的数就可以表示为x+a,x+b,x+c了. 这里 x+a,x+b,x+c是递增的.这里我把这个序列叫做A序列 然后对于给出的k个数,我们也排一下序,这里我把它叫做B序列,如果我

[Codeforces] Round #352 (Div. 2)

人生不止眼前的狗血,还有远方的狗带 A题B题一如既往的丝帛题 A题题意:询问按照12345678910111213...的顺序排列下去第n(n<=10^3)个数是多少 题解:打表,输出 1 #include<bits/stdc++.h> 2 using namespace std; 3 int dig[10],A[1005]; 4 int main(){ 5 int aa=0; 6 for(int i=1;;i++){ 7 int x=i,dd=0; 8 while(x)dig[++dd

Codeforces Round #273 (Div. 2)

Codeforces Round #273 (Div. 2) 题目链接 A:签到,仅仅要推断总和是不是5的倍数就可以,注意推断0的情况 B:最大值的情况是每一个集合先放1个,剩下都丢到一个集合去,最小值是尽量平均去分 C:假如3种球从小到大是a, b, c,那么假设(a + b) 2 <= c这个比較明显答案就是a + b了.由于c肯定要剩余了,假设(a + b)2 > c的话,就肯定能构造出最优的(a + b + c) / 3,由于肯定能够先拿a和b去消除c,而且控制a和b成2倍关系或者消除

Codeforces Round #339 (Div. 2) B. Gena&#39;s Code

B. Gena's Code It's the year 4527 and the tanks game that we all know and love still exists. There also exists Great Gena's code, written in 2016. The problem this code solves is: given the number of tanks that go into the battle from each country, f