FZU1862(线段树 或者 DP)
Accept: 100 Submit: 249
Time Limit: 2000 mSec Memory Limit : 32768 KB
Problem Description
There are N numbers (non-negative integers) in a circle. Now your task is quite simple, just tell me the largest number between L and R.
The Figure 1 is a sample of five integers in a circle. (marked with their index, but not their exact value.)
The Figure 2,3 show how we count the number.
Input
There are no more than 10 test cases;
For each case, the first line contains only one integer N, indicates the size of the circle.
The following one line contains N non-negative integers where Mi indicates the i-th integers whose index is i. (1 <= N <= 1000, 1 <= i <= N, 0 <= Mi <= 10^9)
Then one line contains Q indicates the number of querys. (1 <= Q <= 10^5)
Then the next Q lines, each line contains only two integers indicate L and R (1 <= L,R <= N)
Output
For each case, please output “Case #index:” in a single line, here index is the case index starts from one.
For each query just output a single line indicates the largest number between L and R.
Output a blank line after each case.
Sample Input
Sample Output
Hint
Huge Input, please “scanf” to avoid time limit exceed.
题意:在给定的区间中查询最大的数。当L>R时,R =R +n 来改变R这也是2*n的原因;
方法1:线段树
收获:函数中的num指的是线段树上的编号,而当le == ri时,le 或 ri指的是最低层的编号。
#include <cstdio> #include <iostream> #include <cstdlib> #include <algorithm> #include <ctime> #include <cmath> #include <string> #include <cstring> #include <stack> #include <queue> #include <list> #include <vector> #include <map> #include <set> using namespace std; const int INF=0x3f3f3f3f; const double eps=1e-10; const double PI=acos(-1.0); #define maxn 8006 int tre[maxn]; int a[maxn/4]; int n; void build(int num, int le, int ri) { if(le == ri) { if(le > n) tre[num] = a[le-n];//函数中的num指的是线段树上的编号,而当le == ri时,le 或 ri指的是最低层的编号。 else tre[num] = a[le]; return; } int mid = (le + ri)/2; build(num*2, le, mid); build(num*2+1, mid+1, ri); tre[num] = max(tre[num*2], tre[num*2+1]); } int query(int num,int le,int ri,int x,int y) { if(x<=le&&y>=ri) return tre[num]; int mid=(le+ri)/2; int ans=0; if(x<=mid) ans=max(ans,query(num*2,le,mid,x,y)); //先查询左边 if(y>mid) ans=max(ans,query(num*2+1,mid+1,ri,x,y)); //再查询右边 return ans; } int main() { int cas = 1; while(~scanf("%d", &n)) { for(int i = 1; i <= n; i++) scanf("%d", &a[i]); build(1, 1, 2*n); int m; scanf("%d", &m); int a, b; printf("Case #%d:\n", cas++); for(int j = 0; j < m; j++) { scanf("%d%d", &a, &b); if(b < a) b = b + n; printf("%d\n", query(1, 1, 2*n, a, b)); } puts(""); } }
方法2:DP
收获:对dp有了更多的了解。
dp[i][j]指的是i到j这个区间内保存的最大值。
#include <cstdio> #include <iostream> #include <cstdlib> #include <algorithm> #include <ctime> #include <cmath> #include <string> #include <cstring> #include <stack> #include <queue> #include <list> #include <vector> #include <map> #include <set> #define C 0.57721566490153286060651209 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; typedef long long LL; const int INF=0x3f3f3f3f; const double eps=1e-10; const double PI=acos(-1.0); const int maxn=1000009; int dp[2020][2020]; int a[2020]; int main() { int n, b; int sum=0; while(~scanf("%d", &n)) { for(int i = 1; i <= n; i++) { scanf("%d", &b); a[i]=a[i+n]=b; } for(int i = 1; i <=2*n; i++) { dp[i][i]=a[i]; for(int j=i+1;j<=2*n;j++) { if(a[j]>dp[i][j-1]) dp[i][j]=a[j]; else dp[i][j]=dp[i][j-1]; } } int m; scanf("%d", &m); int L, R; printf("Case #%d:\n",++sum); for(int i=1;i<=m;i++) { int q,w; scanf("%d%d",&q,&w); if(w<q) w=w+n; printf("%d\n",dp[q][w]); } puts(""); } return 0; }