正题
题目大意:https://www.luogu.org/problemnew/show/P3575
题目大意
一个环,上面有若干个点,若干个询问xxx。
表示上一个降落点和下一个降落点距离不能超过xxx,然后求至少要降落多少次(起点可以任意)
解题思路
首先明显环形dpdpdp,然后断环成链,复制一份放到后面,预处理距离前缀和数组sumsumsum。
然后考虑贪心设lastilast_ilasti数组,定义dpidp_idpi表示lasti∼i(i>n)last_i\sim i(i>n)lasti∼i(i>n)这段范围的降落次数,然后优先飞最远。也就是jjj是iii的最前的降落地点。因为jjj满足单调性,所以就可以O(n)O(n)O(n)的预处理出来(或者在dpdpdp的时候处理)。然后首先显然
dpi=dpj+1dp_i=dp_j+1dpi=dpj+1
然后因为计算上了dpjdp_jdpj,所以要从lastjlast_jlastj开始也就是
lasti=lastjlast_i=last_jlasti=lastj
然后当i−lasti>=ni-last_i>=ni−lasti>=n时就是答案了。
codecodecode
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=2000100;
ll n,t,imp;
ll sum[N],dp[N],last[N];
void get_answer(ll l){if(l<imp){printf("NIE\n");return;}for(ll i=n+1,j=1;i<=2*n;i++){while(sum[i]-sum[j]>l) j++;dp[i]=dp[j]+1;last[i]=last[j];if(i-last[i]>=n){printf("%lld\n",dp[i]);return;}}
}
int main()
{scanf("%lld%lld",&n,&t);for(ll i=1;i<=n;i++){last[i]=i;scanf("%lld",&sum[i]);imp=max(imp,sum[i]);sum[i+n]=sum[i];sum[i]+=sum[i-1];}for(ll i=n+1;i<=2*n;i++)sum[i]+=sum[i-1];for(ll i=1;i<=t;i++){ll l;scanf("%lld",&l);get_answer(l);}
}