没啥好说,都是一遍过
1.求最小公倍数
思路:
求lcm。其实就是两数之乘积除以两个数的gcd。gcd就是是求两个数的最大公约数。
代码:
#define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> using namespace std; int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); } int main() { int a, b; cin >> a >> b; cout << (long long)a * b / gcd(a, b) << endl; return 0; }
2.数组中的最长连续子序列
思路:
题目描述有问题,求的答案跟子序列没半毛钱关系。转换一下题意就是,从一堆数里面选出n个数,这n个数排序后是一个严格+1的递增序列。既然和顺序无关,那就可以先sort.。sort完后用双指针维护一个严格+1的递增区间 。考虑到有重复数字的问题,在此之前去重就好了。
这题其实也可以用dp去做,dp[i]表示以i结尾的最长序列有多长,于是dp[i]=max (dp[i-1]+1 ,dp[i])
这里的dp可以用map维护。
代码:
#define _CRT_SECURE_NO_WARNINGS 1 class Solution { public: int MLS(vector<int>& arr) { if (arr.size() == 1)return 1; sort(arr.begin(), arr.end()); arr.erase(unique(arr.begin(), arr.end()), arr.end()); int ans = 0; int i = 1, j = 0; int n = arr.size(); for (; i < n; i++) { if (arr[i] - arr[i - 1] != 1) { ans = max(ans, i - j); j = i; } } if (arr[n - 1] - arr[n - 2] == 1) { ans = max(ans, i - j); } return ans; } };
3.字母收集
思路:
跟杨辉三角没区别。
一般这种dp都是反过来思考的。对于一个(i,j)来说,到达这个点最多有多少分?怎么到达这个点?也就是这个点的上一个状态有哪几种? 只能是dp[i-1][j](表示上面)和dp[i][j-1](左边)来的。所以dp[i][j]就等于这两个状态的最大值。于是轻而易举得到状态转移方程:dp[i][j]=max(dp[i-1][j],dp[i][j-1])+val(arr[i]][j])。注意val表示(i,j)这个点的分数。
简单来说一下对于这种路径dp的思路吧:
假设某种路径问题是,从那里到那里的最大分数啊这种问题。
优先考虑对于当前状态,上一个状态有哪些?
就比如上一道题用dp怎么去想呢?从前往后,到达i这个点的状态有哪些?只能是i-1,所以dp[i]=dp[i-1]+1.
线性dp,区间dp,树上dp基本上都是这么想的。当然具体题目具体的来。
代码:
#include <iostream> using namespace std; const int N=510; char g[N][N]; int f[N][N]; int main() { int n,m; cin>>n>>m; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cin>>g[i][j]; } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ int k=0; if(g[i][j]=='l')k=4; else if(g[i][j]=='o')k=3; else if(g[i][j]=='v')k=2; else if(g[i][j]=='e')k=1; f[i][j]=max(f[i-1][j]+k,f[i][j-1]+k); } } cout<<f[n][m]<<endl; return 0; }