Codeforces Round #619 (Div. 2)
[codeforces 1301D] Time to Run 画图+周期性+你也可以
总目录详见https://blog.csdn.net/mrcrack/article/details/103564004
在线测评地址https://codeforces.com/contest/1301/problem/D
Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|
D - Time to Run | GNU C++11 | Accepted | 31 ms | 0 KB |
笔者如此繁杂的代码,估计很少有人能看得下去。
写此文的目的,告诉各位,I believe I can.
不用看他人代码,思路,各位也一定能编码成功,开始慢一点,不要紧,信心是一点一点建立的。
比较好奇,该题的输出答案五花八门,codeforces是如何判断代码正确与否。望读者不吝赐教。
//明确是个欧拉回路,也即一笔画,该问题,具体到任意一点,入度与出度之和为0
//接下来,画图找规律,确保能经过所有道路。
//基本确认,画图有周期性
//但是a string of moves s of length at most 4.这个4挺难办,要是再大些就更好了
//start from the top-left cell.起点被限,也挺烦。
//存在多种可能的走法,找到符合题意的走法,注意限制a string of moves s of length at most 4.
//因n,m都可以从1开始的,所以该题还得先讨论n,m的范围。
//k>4nm-2n-2m无解。
//讨论n==1
//讨论m==1
//讨论n>=2&&m>=2
由图发现规律如下:
1个周期(上图中1,2,3或者4,5,6对应的路径): m-2个RDU,1个RD(1行);m-1个L;1个UD
边界(上图中7对应的路径).//m-1 R;n-1 U;m-1 L;
编码过程中,提供一组测试样例
AC代码如下
#include <stdio.h>
int n,m,k,a,b;
void period(int m){//1个周期
if(m-2>0)printf("%d RDU\n",m-2);
printf("1 RD\n");
printf("%d L\n",m-1);
printf("1 UD\n");
}
void solve(int n,int m,int k){//n>=2,m>=2,k<=4*n*m-2*n-2*m
int p,step,tot,i;//p一个周期走过的道路数量.tot周期数量
p=(m-2)*3+1*2+(m-1)*1+1*2;//1个周期: m-2个RDU,1个RD(1行);m-1个L;1个UD
step=(m-2>0)+1+1+1;
tot=n-1;
if(k<=tot*p){//在周期范畴内
a+=(k/p)*step,b=k%p;
if(b){
if(b<=(m-2)*3){
if(b%3==0){//整除
a+=1;
printf("%d\n",a);
for(i=1;i<=k/p;i++)period(m);
printf("%d RDU\n",b/3);
}else{//不整除
a+=2;
printf("%d\n",a);
for(i=1;i<=k/p;i++)period(m);
printf("%d RDU\n",b/3);
b%=3;//此处关键,之前错写成b-=(m-2-1)*3;
if(b==1)printf("1 R\n");
else if(b==2)printf("1 RD\n");
}
}else if(b<=(m-2)*3+1*2){
if(m-2>0)a+=2;
else a+=1;//m-2==0
printf("%d\n",a);
for(i=1;i<=k/p;i++)period(m);
if(m-2>0)printf("%d RDU\n",m-2);
b-=(m-2)*3;
if(b==1)printf("1 R\n");
else if(b==2)printf("1 RD\n");
}else if(b<=(m-2)*3+1*2+(m-1)*1){
b-=(m-2)*3+1*2;
if(m-2>0)a+=1+1+1;
else a+=1+1;//m-2==0
printf("%d\n",a);
for(i=1;i<=k/p;i++)period(m);
if(m-2>0)printf("%d RDU\n",m-2);
printf("1 RD\n");
printf("%d L\n",b);
}else if(b<=(m-2)*3+1*2+(m-1)*1+1){
if(m-2>0)a+=1+1+1+1;
else a+=1+1+1;
printf("%d\n",a);
for(i=1;i<=k/p;i++)period(m);
if(m-2>0)printf("%d RDU\n",m-2);
printf("1 RD\n");
printf("%d L\n",m-1);
printf("1 U\n");
}
}else{//b==0
printf("%d\n",a);
for(i=1;i<=k/p;i++)period(m);
}
}else{//k>tot*p要讨论到边界.//m-1 R;n-1 U;m-1 L;
a+=(k/p)*step,b=k%p;
if(b<=(m-1)*1){
a+=1;
printf("%d\n",a);
for(i=1;i<=k/p;i++)period(m);
printf("%d R\n",b);
}else if(b<=(m-1)*1+(n-1)*1){
a+=2;
printf("%d\n",a);
for(i=1;i<=k/p;i++)period(m);
printf("%d R\n",m-1);
b-=m-1;
printf("%d U\n",b);
}else if(b<=(m-1)*1+(n-1)*1+(m-1)*1){
a+=3;
printf("%d\n",a);
for(i=1;i<=k/p;i++)period(m);
printf("%d R\n",m-1);
printf("%d U\n",n-1);
b-=(m-1)+(n-1);
printf("%d L\n",b);
}
}
}
int main(){
int i,j;
scanf("%d%d%d",&n,&m,&k);
if(k>4*n*m-2*n-2*m){//NO的唯一情况,也同时排除了n==1&&m==1的情况
printf("NO\n");
return 0;
}
printf("YES\n");
if(n==1){
if(k<=m-1){//一行水平行进最大距离m-1
printf("1\n");
printf("%d R\n",k);
}
else{ //k>m-1
printf("2\n");
printf("%d R\n",m-1);
printf("%d L\n",k-(m-1));
}
}else if(m==1){//一列竖直行进最大距离n-1
if(k<=n-1){
printf("1\n");
printf("%d D\n",k);
}else{//k>n-1
printf("2\n");
printf("%d D\n",n-1);
printf("%d U\n",k-(n-1));
}
}else if(n>=2&&m>=2) solve(n,m,k);//重点编写,因此种情况复杂,放在一个函数里,比较清晰
return 0;
}