题目链接:https://vjudge.net/contest/341054#problem/C
翻译:
给定三个数n,m,d,分别表示河的长度,木板的数量,人能跳跃的最大距离。
接下来m个数,表示编号为i的木板的长度。
要求,能否通过给定数量的木板,人能从0跳到n+1的位置,若能实现,输出n个数。
注:
这n个数,是将河的长度分成n块,每一块初始化为0,从左到右为1到m块木板。每一块木板占据那一块就把这一部分赋值为这一块木板的编号。
例如上图,河的宽度为7,3块木板,人能跳跃的最大距离为2。第一块木板占据2的位置,将2赋值为1。第2块木板占据4和5的位置,将4和5赋值为2,第三块木板占据7的位置,将7赋值为3。输出7个数:0 1 0 2 2 0 3
分析:
刚开始把木板全部放在最右边,并进行标号。
now表示当前位置,起初now=0。
第一次跳最大距离now+=d;若now此时还没有木板,就找到所有木板的最左边并计算这个木板的长度,把木板移动到now的位置。
代码:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=1e3+10;
int main()
{
int n,m,d;
//河的宽度n,m个木板,人最大的跳跃距离
while(~scanf("%d%d%d",&n,&m,&d))
{
int c[N],ans[N];
memset(c,0,sizeof(c));
memset(ans,0,sizeof(ans));/*对每一块进行标号*/
for(int i=0; i<m; i++)
scanf("%d",&c[i]);
//把所有的木板放到最右边
for(int i=m-1,pos=n; i>=0; i--)
{
for(int len=0; len<c[i]; len++)
ans[pos-len]=i+1;
pos-=c[i];
}
int now=0;
while(1)
{
//now表示此刻的位置,while表示借助木板能到达的最右边
//起初若木板没有铺到最左边,就不执行while循环,now=0
while(now+1<n+1&&ans[now+1]>0)
++now;
if(now+d>=n+1)
break;
//now=0是,跳最大距离d,now+d的位置依然没有木板
if(ans[now+d]==0)
{
int lpos=-1;
//找到木板的最左边
for(int i=now+d; i<n+2; i++)
if(ans[i]!=0)
{
lpos=i;
break;
}
if(lpos==-1)
{
printf("NO\n");
return 0;
}
//这个木板的长度
int rpos=-1;
for(int i=lpos; i<n+2; i++)
if(ans[i]==ans[lpos])
rpos=i;
//把木板移到左端为0的位置
while(ans[now+d]==0)
{
swap(ans[lpos-1],ans[rpos]);
lpos--,rpos--;
}
}
now+=d;
}
printf("YES\n");
for(int i=1; i<=n; i++)
printf("%d ",ans[i]);
printf("\n");
}
return 0;
}