UVA11078 Open Credit System
大致题意
给一个长度为n的整数序列a0 a1 a2….an-1,找出两个整数ai和aj(i < j) 使得ai-aj最大 输入
第一行 组数 T 每组数据 第一行输入数据数量n(2<=n<=1e+5) 接下来是n个不超过150000的整数 输出
对于每组数据,输出最大ai-aj。
题目价值;
- 学会找到题目解答的关键。
- 本题n^2解法是两个for循环,然后逐个比较答案。但是仔细分析题目会发现:题目要求的只是j之前的一个最大值。所以题目关键是a[j]之前的最大值,所以只要每次与更新最大值maxn就好了,优化为o(n)。
UVA11549 Calculator Conundrum
题意:把k反复平方,只留前n位,求在乘的过程中的max。
题目价值
- 发现题目特性:平方后截断的数有循环性。
- 引入floyd判圈法:
- 如果是循环出现,或者环状数据结构。两个人从相同的起点,最终会相遇。
- -
UVA1121 Subsequence
题意:n个正整数组成的序列,求最短的字串和为s
- 朴素算法 n^3枚举开头结尾和累加
- 前缀数组优化为n^2 (TLE)
- 由sum[j] - sum[i-1] >= s =>sum[i-1] <=sum[i] - s; 所以只枚举j,因为sum数组单调递增,所以用二分查找找i。nlogn(AC)
- 因为sum单调,i也单调。优化为n。
code1
o(n^2)
#include<bits/stdc++.h>
using namespace std;
#define N 100000 + 10
int a[N],n,s;
int sum[N];
int main() {
while (scanf("%d%d",&n,&s) == 2) {
for (int i = 1; i<= n ;i++) {
scanf("%d",&a[i]);
sum[i] = a[i] + sum[i-1];
}
int ans = N*1000;
for (int i = 1;i <=n;i++)
for(int j = i + 1;j <=n ;j++)
{
if(sum[j] - sum[i - 1] >= s)ans = min (ans,j - i + 1);
}
printf("%d\n",ans == N*1000? 0 : ans);
}
return 0;
}
code2
o(nlogn)
int ans = N*1000;
for(int j = 1;j <=n ;j++)
{
int i = lower_bound(sum,sum + j,sum[j] - s) - sum;
if(i > 0)ans = min (ans,j - i + 1);
}
code3
o(n)
for(int j = 1;j <=n ;j++)
{
if(sum[i-1] > sum[j] - s)continue;
while(sum[i] <= sum[j] - s)i++;
ans = min(ans,j - i + 1);
}
UVA10755 Garbage Heap
大意:A×B×C的长方体,价值以(1,1,1)(1,1,2)…(1,1,C)..(1,2,1)..(1,2,C)给出。求价值最大的子立方体;
关键词 : 降维,前缀和。
题目价值
- 解决高维问题一般方法是降维再推广到多维上来。
- 题目基础是最大连续字段和,此处拓展到3维。
- 题目求解分为两部分:
- 一.求前缀数组。
- 二.最大连续字段和。