#include<iostream>usingnamespace std;constint N =110;int n, m;int arr[N][N];int dp[N][N]={0};int dx[4]={0,0,1,-1};int dy[4]={1,-1,0,0};intdfs(int i,int j){if(dp[i][j]){return dp[i][j];}int len =1;for(int k =0; k <4; k++){int x = i + dx[k];int y = j + dy[k];if(x >=1&& x <= n && y >=1&& y <= m && arr[x][y]< arr[i][j]){len =max(len,dfs(x, y)+1);}}dp[i][j]= len;return len;}intmain(){cin >> n >> m;for(int i =1; i <= n; i++){for(int j =1; j <= m; j++){cin >> arr[i][j];}}int ret =1;for(int i =1; i <= n; i++){for(int j =1; j <= m; j++){ret =max(ret,dfs(i, j));}}cout << ret << endl;return0;}
2. Day38
2.1 天使果冻(递推 + DP)
题目链接: 天使果冻
题目描述:
解法:
算法思路:需要两个数组来保存最大值和次大值,当新的元素进来就有三种情况:
第一种就是比最大值还大。
第二种就是大于次大值小于最大值。
第三种是比次大致小。但是第三种情况不是不更新,而是把前面的最大值和次大值要保存的后面来。
C++ 算法代码:
#include<iostream>#include<algorithm>usingnamespace std;constint N =1e5+10;int sp[N];int f[N];int g[N];intmain(){int n =0;cin >> n;for(int i =0; i < n; i++){cin >> sp[i];}f[0]= sp[0];g[0]=-1;for(int i =1; i < n; i++){f[i]=max(f[i -1], sp[i]);if(sp[i]>= f[i -1]){g[i]= f[i -1];}elseif(sp[i]>= g[i -1]&& sp[i]< f[i -1]){g[i]= sp[i];}else{g[i]= g[i -1];}}int q =0;cin >> q;while(q--){int x =0;cin >> x;cout << g[x -1]<< endl;}return0;}
2.2 dd爱旋转(模拟)
题目链接: dd爱旋转
题目描述:
解法:
算法思路:模拟题,但是需要不能直接无脑模拟,要思考⼀下规律~
C++ 算法代码:
#include<iostream>usingnamespace std;constint N =1010;int n;int g[N][N];voidsetRow(){for(int i =0; i < n /2; i++){for(int j =0; j < n; j++){swap(g[i][j], g[n -1- i][j]);}}}voidsetCol(){for(int j =0; j < n /2; j++){for(int i =0; i < n; i++){swap(g[i][j], g[i][n -1- j]);}}}intmain(){cin >> n;for(int i =0; i < n; i++){for(int j =0; j < n; j++){cin >> g[i][j];}}int q =0;cin >> q;int row =0;int col =0;while(q--){int x =0;cin >> x;if(x ==1){row++;col++;}else{row++;}}row %=2;col %=2;if(row){setRow();}if(col){setCol();}for(int i =0; i < n; i++){for(int j =0; j < n; j++){cout << g[i][j]<<" ";}cout << endl;}return0;}
2.3 小红取数(动态规划 - 01 背包 + 同余)
题目链接: DP40 小红取数
题目描述:
解法:
算法思路:这道题是不能用空间优化的~
dp[i][j]表示:前i个数中挑选,总和 %k等于 j 时,最大和是多少。j 表示的是余数。
C++ 算法代码:
#include<iostream>#include<cstring>usingnamespace std;constint N =1010;intmain(){int n, k;cin >> n >> k;longlong arr[N];for(int i =1; i <= n; i++){cin >> arr[i];}longlong dp[N][N];memset(dp,-0x3f,sizeof dp);dp[0][0]=0;for(int i =1; i <= n; i++){for(int j =0; j < k; j++){dp[i][j]=max(dp[i -1][j], dp[i -1][(j - arr[i]% k + k)% k]+ arr[i]);// j - arr[i] % k可能是负数,所以加上k修正,后面%k是修正本来是正数的值}}if(dp[n][0]<=0){cout <<-1<< endl;}else{cout << dp[n][0]<< endl;}return0;}
#include<iostream>#include<cstring>usingnamespace std;constint N =1e4+0;intmain(){int n =0;cin >> n;int dp[N]={0};memset(dp,0x3f,sizeof dp);dp[0]=0;for(int i =1; i * i <= n; i++){for(int j = i * i; j <= n; j++){dp[j]=min(dp[j], dp[j - i * i]+1);}}cout << dp[n]<< endl;return0;}
4. Day40
4.1 游游的字母串(枚举)
题目链接: 游游的字母串
题目描述:
解法:
算法思路:枚举所有可能变成的字符情况。
C++ 算法代码:
#include<iostream>usingnamespace std;intmain(){string s;cin >> s;int ret =1e9;for(char ch ='a'; ch <='z'; ch++){int sum =0;for(auto x : s){sum +=min(abs(x - ch),26-abs(x - ch));}ret =min(ret, sum);}cout << ret << endl;return0;}
4.2 体育课测验(二)(拓扑排序)
题目链接: NC316 体育课测验(二)
题目描述:
解法:
算法思路:简单拓扑排序的应⽤。
C++ 算法代码:
classSolution{public:vector<int>findOrder(int n, vector<vector<int>>& groups){vector<vector<int>>edges(n);// 存储边vector<int>in(n);// ⼊度// 1. 建图for(auto v : groups){int a = v[0], b = v[1];// b -> aedges[b].push_back(a);in[a]++;}queue<int> q;// 2. ⼊度为 0 的点,加⼊到队列⾥⾯for(int i =0; i < n; i++){if(in[i]==0){q.push(i);}}// 3. 拓扑排序vector<int> ret;while(q.size()){int a = q.front();q.pop();ret.push_back(a);for(auto b : edges[a]){// a -> bif(--in[b]==0){q.push(b);}}}if(ret.size()== n){return ret;}else{return{};}}};
4.3 合唱队形(动态规划)
题目链接: DP16 合唱队形
题目描述:
解法:
算法思路:最长上升子序列模型。
C++ 算法代码:
#include<iostream>usingnamespace std;constint N =1010;int n;int arr[N], f[N], g[N];intmain(){cin >> n;for(int i =1; i <= n; i++) cin >> arr[i];// 从前向后for(int i =1; i <= n; i++){f[i]=1;for(int j =1; j < i; j++){if(arr[j]< arr[i]){f[i]=max(f[i], f[j]+1);}}}// 从后向前for(int i = n; i >=1; i--){g[i]=1;for(int j = i +1; j <= n; j++){if(arr[i]> arr[j]){g[i]=max(g[i], g[j]+1);}}}int len =0;for(int i =1; i <= n; i++){len =max(len, f[i]+ g[i]-1);}cout << n - len << endl;return0;}
5. Day41
5.1 棋子翻转(模拟)
题目链接: MT2 棋子翻转
题目描述:
解法:
算法思路。模拟即可。注意点:
如何访问上下左右四个⽅向;
访问的时候不要越界;
下标的对应关系; 如何优雅地翻转~
C++ 算法代码:
classSolution{public:int dx[4]={0,0,1,-1};int dy[4]={1,-1,0,0};vector<vector<int>>flipChess(vector<vector<int>>& A, vector<vector<int>>& f){for(auto& v : f){int a = v[0]-1, b = v[1]-1;for(int i =0; i <4; i++){int x = a + dx[i], y = b + dy[i];if(x >=0&& x <4&& y >=0&& y <4){A[x][y]^=1;}}}return A;}};
5.2 宵暗的妖怪(动态规划)
题目链接: 宵暗的妖怪
题目描述:
解法:
算法思路:打家劫舍,但是别抢到最后⼀家就行了~
C++ 算法代码:
#include<iostream>usingnamespace std;constint N =1e5+10;int n;longlong arr[N];longlong dp[N];intmain(){cin >> n;for(int i =1; i <= n; i++){cin >> arr[i];}for(int i =3; i <= n; i++){dp[i]=max(dp[i -1], dp[i -3]+ arr[i -1]);}cout << dp[n]<< endl;return0;}
5.3 过桥(BFS)
题目链接: 过桥
题目描述:
解法:
算法思路:类似层序遍历的思想。
C++ 算法代码:
#include<iostream>usingnamespace std;constint N =2010;int n;int arr[N];intbfs(){int left =1;int right =1;int ret =0;while(left <= right){ret++;int r = right;for(int i = left; i <= right; i++){r =max(r, arr[i]+ i);if(r >= n){return ret;}}left = right +1;right = r;}return-1;}intmain(){cin >> n;for(int i =1; i <= n; i++){cin >> arr[i];}cout <<bfs()<< endl;return0;}
6. Day42
6.1 最大差值(模拟 + 贪心)
题目链接: MT1 最大差值
题目描述:
解法:
算法思路:遍历数组的过程中,使用一个变量标记⼀下当前位置之前所有元素的最小值即可。
C++ 算法代码:
classSolution{public:intgetDis(vector<int>& arr,int n){int ret =0;int minPrev = arr[0];for(int i =1; i < n; i++){minPrev =min(minPrev, arr[i]);ret =max(ret, arr[i]- minPrev);}return ret;}};
6.2 兑换零钱(动态规划 - 完全背包)
题目链接: DP44 兑换零钱
题目描述:
解法:
算法思路:完全背包问题。
C++ 算法代码:
#include<iostream>#include<cstring>usingnamespace std;constint N =10010, M =5010;int n, aim;int arr[N];int dp[M];intmain(){cin >> n >> aim;for(int i =1; i <= n; i++){cin >> arr[i];}memset(dp,0x3f,sizeof dp);dp[0]=0;for(int i =1; i <= n; i++){for(int j = arr[i]; j <= aim; j++){dp[j]=min(dp[j], dp[j - arr[i]]+1);}}if(dp[aim]>=0x3f3f3f3f){cout <<-1<< endl;}else{cout << dp[aim]<< endl;}return0;}
#include<iostream>#include<string>usingnamespace std;int n, l, r;
string s;// 找出字符种类在 [1, x] 之间的⼦串的个数longlongfind(int x){if(x ==0){return0;}// 滑动窗⼝int left =0;int right =0;int hash[26]={0}int kinds =0;// 统计窗⼝内字符种类的个数longlong ret =0;while(right < n){if(hash[s[right]-'a']++==0){kinds++;}while(kinds > x){if(hash[s[left]-'a']--==1){kinds--;}left++;}ret += right - left +1;right++;}return ret;}intmain(){cin >> n >> l >> r >> s;cout <<find(r)-find(l -1)<< endl;return0;}