「高效算法设计」

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维。
  • 题目求解分为两部分:
  • 一.求前缀数组。
  • 二.最大连续字段和。

猜你喜欢

转载自blog.csdn.net/k42946/article/details/81274716