Codeforces Round #632 (Div. 2) 比赛人数12810
[codeforces 1333D] Challenges in school №41 在整体移动中,记录个体移动的信息
总目录详见https://blog.csdn.net/mrcrack/article/details/103564004
在线测评地址https://codeforces.com/contest/1333/problem/D
Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|
D - Challenges in school №41 | GNU C++17 | Accepted | 358 ms | 35500 KB |
该题最大的亮点,就是,在整体移动中,记录个体移动的信息
手工算法如下
造了一组样例,如下
8 10
RRRLLRLL
字母数组脚标 12345678
原始数据 RRRLLRLL
第1次整体移动 RRLRLLRL记录移动的个体步骤(3,4),(6,7) 个体移动次数2次
第2次整体移动 RLRLRLLR记录移动的个体步骤(2,3),(4,5),(7,8) 个体移动次数3次
第3次整体移动 LRLRLRLR记录移动的个体步骤(1,2),(3,4),(5,6) 个体移动次数3次
第4次整体移动 LLRLRLRR记录移动的个体步骤(2,3),(4,5),(6,7) 个体移动次数3次
第5次整体移动 LLLRLRRR记录移动的个体步骤(3,4),(5,6) 个体移动次数2次
第6次整体移动 LLLLRRRR记录移动的个体步骤(4,5) 个体移动次数1次
可以看到最少移动次数6次
最多移动次数2+3+3+3+3+2+1=14次
k=10可这样操作
1 3
1 6
1 2
1 4
1 7
1 1
2 3 5
3 2 4 6
2 3 5
1 4
明白上述手工算法后,再结合如下AC代码,应该能很快解决该题。
#include <cstdio>
#include <algorithm>
#define maxn 3010
using namespace std;
int n,k,mx,mn;//mx最多步数,mn最少步数
char s[maxn];
int a[maxn][maxn];//a[i][j]表示在第i次整体移动中,对应的第j次个体移动.为了照顾程序的可读性,就不采用邻接表的方式进行记录了
int right[maxn];
int judge(){//返回值,1还需move,0无需move
int i;
for(i=1;i<n;i++)
if(s[i]=='R'&&s[i+1]=='L')//存在面对面的情况
return 1;
return 0;
}
void move(){
int i,r=0;
mn++;//整体的移动次数
for(i=1;i<n;i++)
if(s[i]=='R'&&s[i+1]=='L'){//个体的移动
mx++;//个体的移动次数
r++;
a[mn][r]=i;//记录一步一步的移动,对应的位置
}
for(i=1;i<=r;i++)swap(s[a[mn][i]],s[a[mn][i]+1]);//turns left and vice versa 就相当与交换
right[mn]=r;
}
int main(){
int l,r,i,j;
scanf("%d%d%s",&n,&k,s+1);
while(judge())move();
if(k<mn||mx<k){printf("-1\n");return 0;}
k-=mn;
for(i=1;i<=mn;i++){//从整体移动中分解出独立步骤
l=1,r=right[i];
while(k&&l<r){//个体的移动
printf("1 %d\n",a[i][l]);
k--,l++;
}
printf("%d",r-l+1);//整体的移动
for(j=l;j<=r;j++)printf(" %d",a[i][j]);
printf("\n");
}
return 0;
}