0
点赞
收藏
分享

微信扫一扫

【51Nod 1319】跳跃游戏


Description

有一个可以在二维平面上做跳跃的机器人,该机器人有独特的跳跃程序。该程序的跳跃距离是由一个循环序列S决定的。序列S有无穷多项,但其有一个最小周期序列,令其为A,A中有N个元素(N<=50),S[i]=A[i mod N],i从0取到正无穷。例如,A={2,5,1,1}那么S={2,5,1,1,2,5,1,1,2,5,1,1…..}。机器人的跳跃规则如下:第k次跳跃时,机器人可以跳出离原来位置S[k]的距离外,方向随意,其中k=0,1,2,3,…。这个方向是由机器人的控制玩家自己决定的,它可以是0~360度内的任意一个方向,角度未必是整数,落点也未必是整点。注意,控制玩家不能控制跳跃的距离,这个距离是机器人的自身属性即A序列决定的;玩家只能决定每一次跳跃的方向。现在,你需要让机器人从平面的(0,0)处跳跃到(x,0)处,求出最少需要控制机器人跳跃几次。其中,初始(第0次)跳跃距离恰为S[0]。
例如:x=5,A={3,4},(0,0)->(9/5,12/5)->(5,0)。

Solution

题意就是构造一个底为x,由一组循环数组的边构成的多边形。
不会做,感觉自己好弱,看了看题解……
设现在所有的边加起来和为t,那么首先要满足的就是t≥x。然后一个多边形可以拆成很多了小的三角形,那么根据三角形的边的不等式关系,可以知道t+x≥2*mx(所选的边的最大边)。
如果ans是<2*n的,直接按照上面的做就好了。
否则,如果ans≥2*n,那么只要满足t≥x就一定能够造出一个多边形,因为每条边至少用两次,那么最坏的情况就是一个等腰三角形。

Code

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=57;
ll i,j,k,l,t,n,m,ans,cas,x;
ll a[maxn],b[maxn];
int main(){
//freopen("fan.in","r",stdin);
for(scanf("%lld",&cas);cas;cas--){
scanf("%lld%lld",&x,&n);l=0;x=abs(x);
memset(b,0,sizeof(b));
fo(i,1,n)scanf("%lld",&a[i]),b[i]=max(b[i-1],a[i]),l+=a[i];
t=0;ans=0;
ans=ans+x/l*n;t=t+x/l*l;
if(!x){
printf("0\n");continue;
}
if(ans<2*n){
ans=t=0;
fo(i,1,2*n){
t+=a[(i-1)%n+1];
ans++;
if(t>=x&&t+x>=2*b[min(n,i)]){
break;
}
}
printf("%lld\n",ans);
continue;
}
fo(i,1,n){
if(t>=x)break;
t+=a[i];
ans++;
}
printf("%lld\n",ans);
}
}


举报

相关推荐

0 条评论