vijos 1471 线性DP+贪心

描述

Orz教主的成员为教主建了一个游乐场,在教主的规划下,游乐场有一排n个弹性无敌的跳跃装置,它们都朝着一个方向,对着一个巨大的湖,当人踩上去装置可以带你去这个方向无限远的地方,享受飞行的乐趣。但是等这批装置投入使用时,却发现来玩的人们更喜欢在这些装置上跳来跳去,并且由于这些装置弹性的优势,不但它们能让人向所对的方向能跳很远,也都能向相反方向跳一定的距离。 于是教主想出了个游戏,这n个装置按朝向相反的方向顺序以1..n编号。第i个装置可以跳到1..i-1个装置,且每个装置有一个不一定相同的反方向弹性a[i],代表第i个装置还可以跳到第i+1..i+a[i]个装置。教主指定一个起始的装置,问从这个装置开始,最少需要连续踩几次装置(起始的装置也算在内),可以跳到第n个装置的后方,即若第k个装置有k+a[i]>n,那么从第k个装置就可以跳到第n个装置的后方。

(PS:你可以认为有n+1个装置,即需要求多少次能条到第n+1个装置)

格式

输入格式

输入的第1行包含两个正整数n,m,为装置的数目以及询问的次数。

第2行包含n个正整数,第i个正整数为a[i],即第i个装置向反方向最大跳跃的长度。

第3行包含了m个正整数,为询问从哪一个装置开始,最少要几次跳到第n个的后方。

数字之间用空格隔开。 输出格式 输出包含1行,这一行有m个正整数,对于每一个询问,输出最少需要踩的装置数,数字之间用空格隔开。

行末换行且没有多余的空格。

样例1

样例输入

1

5 5

2 4 1 1 1

1 2 3 4 5

样例输出

1 2 1 2 2 1

限制

对于20%的数据,有n≤10;

对于40%的数据,有n≤100,m≤10;

对于60%的数据,有n≤1000,a[i]≤1000,m≤500;

对于100%的数据,有n≤100000,a[i]≤n,m≤40000。

时限1s

提示 若从第1个装置开始则跳到第2个装置,接着就可以跳到第n个装置的后方。 若从第3个装置开始则同样跳到第2个装置。 若从第4个装置开始可以跳到第2个装置或最后一个装置,接着跳出第n个装置,答案同样为2。

题意:中文题。

思路:不断从左到右,直到找到一个能跳到右边界r外的位置,定它为左边界l,dp[l] = dp[r] + 1,在 l 到 r 间的位置间进行判断,如果某个位置能够跳到右边界外,那么说明该位置可以通过跳到右边界再跳到下一个位置,即步数dp[i] = dp[r] + 1,而如果不能跳到右边界,那么通过左边界跳到右边界,即dp[i]=dp[l]+1,题目的单调性使这样的策略可行。

/** @Date    : 2016-11-18-13.59
  * @Author  : Lweleth (SoungEarlf@gmail.com)
  * @Link    : https://github.com/
  * @Version :
  */
#include <stdio.h>
#include <iostream>
#include <string.h> #include <algorithm> #include <utility> #include <vector> #include <map> #include <set> #include <string> #include <stack> #include <math.h> #include <queue> //#include<bits/stdc++.h> #define LL long long #define MMF(x) memset((x),0,sizeof(x)) #define MMI(x) memset((x), INF, sizeof(x)) using namespace std; const int INF = 0x3f3f3f3f; const int N = 1e6+2000; using namespace std; //high[i] means pi(n/i),low[i] means pi(i) LL high[340000]; LL low[340000]; LL n; LL fun() { LL i,m,p,s,x; for(m = 1; m * m <= n; m++) high[m] = n/m-1; for(i = 1;i <= m; i++) low[i] = i-1; for(p = 2; p <= m; p++) { if(low[p] == low[p-1]) continue; s = min(n/(p*p),m-1); for(x = 1; x <= s; x++) { if(x*p <= m-1) high[x] -= high[x*p] - low[p-1]; else high[x] -= low[n/(x*p)] - low[p-1]; } for(x = m; x >= p*p; x--) low[x] -= low[x/p] - low[p-1]; } } int main() { while(cin>>n) { fun(); cout << high[1] << endl; } }
原文地址:https://www.cnblogs.com/Yumesenya/p/6107806.html