3-1.LIS(longest increas sequence)不多说,题目说了要($ O(n^2) $),我还能说什么呢?
相同题目:HDU 1087 super jumping !jumping!jumping! 而且不卡平方的做法
用dp[i]表示以 i 个数结尾的序列的LIS长度,初始化为dp[i] = 1 ($ 1 \leq i \leq n $)下面附一神代码
1 # include <iostream> 2 # include <cstdio> 3 # include <algorithm> 4 using namespace std; 5 int num[5005],d[5005]; 6 7 int main(void) 8 { 9 int n; cin>>n; 10 for(int i=0;i<n;i++) scanf("%d",num+i); 11 for(int i=0;i<n;i++) 12 { 13 d[i]=1; 14 for(int j=0;j<i;j++) 15 if(num[j]<=num[i]) d[i]=max(d[i],d[j]+1); 16 } 17 int ans=0; 18 for(int i=0;i<n;i++) ans=max(ans,d[i]); 19 printf("%d\n",ans); 20 return 0; 21 }
Aguin
3-2. 依旧LIS,不过要求 $ O(log(n)) $的算法。
用 dp[cnt]保存长度为cnt的LIS中最后一个数最小的那个数,刚开始,dp[1]为序列中最小的数,对于 num[i]($ 2 \leq i $),如果num[i] > dp[1] ,则dp[2] = num[i],否则,在dp数组中找到比num[i]大的数中最小的那个数(dp数组是有序的,直接二分就ok)更新dp数组:dp[找到的位置] = num[i],最后cnt就是答案啊!
相同题目:NYOJ 17 单调递增最长子序列 很棒的一个题目,平方做法不能AC
1 2 /************************************************************************* 3 > File Name: lis.cpp 4 > Author: 5 > Mail: 6 > Created Time: 2016年03月27日 星期日 20时59分03秒 7 ************************************************************************/ 8 9 #include <iostream> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <cstring> 13 #include <algorithm> 14 #include <cmath> 15 16 using namespace std; 17 const int maxn = 10010 ; 18 char s[maxn] , d[maxn] ; 19 20 inline int reads() 21 { 22 int i = 0 ; 23 char c = getchar() ; 24 if (c == ‘\n‘) c = getchar() ; 25 while (c != ‘\n‘) { 26 s[++i] = c ; 27 c = getchar() ; 28 } 29 return i ; 30 } 31 32 int main() 33 { 34 // freopen("in","r",stdin) ; 35 int T , len ; 36 scanf("%d",&T) ; 37 while (T --) { 38 len = reads() ; 39 d[1] = s[1] ; 40 int cnt = 1 ; 41 for (int i = 2 ; i <= len ; ++ i) { 42 if (s[i] > d[cnt]) d[++cnt] = s[i] ; 43 else { 44 int pos = lower_bound(d+1,d+1+cnt,s[i]) - d ; 45 d[pos] = s[i] ; 46 } 47 } 48 printf("%d\n",cnt) ; 49 } 50 return 0 ; 51 }
CROSShh
3-3. 题意:有两台机器处理N个任务,任务i在如果机器A上处理要花$ a_{i} $时间,在B花$ b_{i} $时间,两台机器可以同时工作,同一个任务只处理一次即可。求最少要花多长时间处理所有任务。
任务 i 要么在 A 处理,要么在 B 处理,我们考虑前 i-1 个任务已经处理了,机器 A 的结束时间为 TimeA , 机器 B 的结束时间为 TimeB,那么,
- 在 A 处理总的结束时间为 max(TimeA+$ a_{i} $,TimeB}。
- 在 B 处理总的结束时间为 max(TimeB+$ b_{i} $,TimeA}。
当然选最小的啦(对于第一个任务来说TimeA=TimeB=0)。代码略==有空再写吧!
3-4. 题意:设有 N 种不同面值的硬币,记为T[i],现在用这些硬币来找钱,各种硬币个数不限
Q_A:当只用前 i 个硬币时,可以找出钱数 j 的最少硬币个数记为C(i,j),找不出则C(i,j) = 无穷大,给出C(i,j)的递归表达式和初始条件。1 << i << N , 1 <= j <= L ;
Q_B: 设计算法,对于1 <= j <= L,计算出C(n,j),只允许用数组L,T,并给出时间复杂度
Q_C: 在C(n,j)已知的情况下,设计贪心算法,对钱数 m (m <= L)给出求C(n,m)的办法,时间复杂度应为O(n+C(n,m))
3-5. 用 "<" , "=",把三个数A,B,C依序排列,有13种不同的序关系
A = B = C , A = B < C , A < B = C , A < B < C , A < C < B
A = C < B , B < A = C , B < A < C ,B < C < A , B = C < A
C < A = B , C < A < B,C < B < A
现在有 n 个数,问有多少种序关系(时间复杂度要求O(n^2),空间复杂度要求O(n))
3-6. 暂无
3-7. 暂无
3-8. 题意:给出A,B两个字符串,目的是把转换成B,问最小的操作次数,满足以下三种操作:
- 删除一个字符
- 插入一个字符
- 把一个字符变成另一个字符
题目说的操作我理解为只能对A操作,那么,必须要满足:
- 能不操作的就尽量不操作
- 能改变的就不使用删除和插入操作
所以,答案就是max(A.length,B.length) - LCSlength(A,B).
3-9. 题意:经典的石子合并问题,可以用四边形优化到平方
参考链接:ACdreamer石子合并问题
和矩阵连乘是同样的类型:dp[i][j] = max(dp[i][k] + dp[k+1][j]+sum[i][j])。sum[i][j] 表示从 i 到 j 的石子的总个数
我更青睐于在最后一堆石子后面添加 N 堆石子,这样只需要找到max(dp[i][i+N-1]),也是一样的。
3-10. 题意:数塔(数字三角形)
自顶向上递推即可dp[i][j] += max(dp[i+1][j],dp[i+1][j+1]),注意一下边界
3-11. 题意:完全背包
参考链接:背包九讲 (提取码:d16f)
for i = 1 ; i <= N ; ++ i for v = cost[i] ; v <= vmax ; v ++ dp[v] = max(dp[v],dp[v-v[i]]+value[i])
3-12. 题意:二维费用的背包,上个题目的资料中有!
dp[i][v][d] = max(dp[i-1][v][d],dp[i][v-v[i]][d-d[i]] + val[i])
3-13. 给了一个特殊的乘法表:
== | a | b | c |
a | b | b | a |
b | c | b | a |
c | a | c | c |
即:aa = b,ab = b ,ac = a , ba = c,bb = b ,bc = a,ca = a,cb = c,cc = c;
让干的是:给出一个由abc组成的字符串,问加括号后最终是 a 的方案数.类似矩阵连乘
dp[a][i][j] = dp[a][i][k]*dp[c][k+1][j] + dp[b][i][k]*dp[c][k+1][j] + dp[c][i][k] + dp[a][k+1][j]
dp[b][i][j] = dp[a][i][k]*dp[a][k+1][j] + dp[a][i][k]*dp[b][k+1][j] + dp[b][i][k]*dp[b][k+1][j]
dp[c][i][j] = dp[b][i][k]*dp[a][k+1][j] + dp[c][i][k]*dp[b][k+1][j] + dp[c][i][k]*dp[c][k+1][j]
3-14. 暂无
3-15. 暂无
3-16. 给定一个N*N的网格,左上角为起点 S (1,1),一辆汽车要从左上角走到右下角(只能走网格边),遵循以下规则:
- 满油能走的距离是 K ,
- 若逆向(X 或 Y 坐标减小)行驶花费 B
- 遇油库就加满油,花费 A
- 可以任意增设油库,花费 C (不含加油费)
目的是从左上角走到右下角且花费最小.
dis[i][j]表示从上次满油状态走到位置(i,j)的距离
dp[i][j] 表示走到位置(i,j)的最小花费.
dp[i][j] = min(dp[i][j-1],dp[i-1][j],dp[i+1][j] + B,dp[i][j+1] + B) ;
dis[i][j] = dis[x][y] ++ ;//x , y 为dp中选择的i,j
if (i,j) 是个油库,dp[i][j] += A , dis[i][j] = 0 ;
else if dis[i][j] == k {
//新建油库且加油
dp[i][j] += (A+C)
dis[i][j] = 0 ;
}
3-17. 题意:给定一个 M*N 的网格,目的是从左上角到右下角,网格边有权值,某些网格点处有障碍物不能走,设计算法,求路径的最小权值和
类似3-16,不能走设为无穷大,
if (dp[i][j] == inf) continue;
else dp[i][j] = min(dp[i][j-1] + val[][],dp[i][j+1]+val[][],dp[i-1][j]+val[][],dp[i+1][j]+val[][])
3-18. 关于整数的二元运算符"#"定义为:
(X # Y) = 十进制整数 X 的各位数字之和 * 十进制整数 Y 中最大的数字 + Y 中的最小数字
例如:(9 # 30) = 9*3 + 0 = 27;
问题:对于给定的十进制整数 X 和 K,由X 和 #运算可以组成各种不同的表达式,计算由 X 和 # 运算组成的值为 K 的表达式至少需要多少个 #
~end~