日常刷题2025-3-1
1.日常刷题2025-3-162.日常训练2025-1-23.日常训练2025-1-34.日常训练2025-1-55.日常训练2025-1-86.日常训练2025-1-117.日常训练2025-1-128.日常训练2025-1-139.日常训练2025-1-1410.日常训练2025-1-1511.日常训练2025-1-1612.日常训练2025-1-1713.日常训练2025-1-1814.日常训练2025-1-1915.日常训练2025-1-2116.日常训练2025-1-2217.日常刷题2025-1-2318.日常训练2025-1-2419.日常刷题2025-1-2520.日常刷题21.日常刷题2025-2-622.日常刷题2025-2-923.日常刷题2025-2-1424.日常刷题2025-2-1525.日常刷题2025-2-1726.日常刷题2025-2-2027.日常刷题2025-2-2128.日常刷题2025-2-2229.日常刷题2025-2-2430.日常刷题2025-2-2631.日常刷题2025-2-2732.日常刷题2025-2-28
33.日常刷题2025-3-1
34.日常刷题2025-3-235.日常刷题2025-3-336.日常刷题2025-3-537.日常刷题2025-3-638.日常刷题2025-3-739.日常刷题2025-3-840.日常刷题2025-3-941.日常刷题2025-3-1042.日常刷题2023-3-1143.日常刷题2025-3-1344.非常棒的二分和DP日常刷题2025-3-1
完美串
111 / 486
思路:构造
此题是一道让相同的字符相隔尽量远的构造,构造时每次选择剩余最多且在 kk 长度以内不冲突的字符构建即可。
构造思路非常值得学习
评述
想到了题目做法但是不会写代码
代码
#include <bits/stdc++.h> typedef std::pair<long long, long long> pll; typedef std::pair<int, int> pii; #define INF 0x3f3f3f3f #define MOD 998244353 using i64 = long long; const int N = 1e5+5; void solve(){ std::string s; std::cin >> s; int n = s.size(); std::vector<pii> p(30); std::vector<int> ans; std::vector<int> a(26); for (auto e : s) a[e-'a']++; auto check = [&](int mid)->bool{ ans.clear(); std::priority_queue<pii> q; for (int i = 0; i < 26; i++) if (a[i]) q.push({a[i], i}); while (1){ if (q.size() < mid){ while (q.size()){ pii t = q.top(); q.pop(); ans.push_back(t.second); if (t.first > 1) return 0; } return 1; } for (int i = 1; i <= mid; i++){ pii t = q.top(); q.pop(); ans.push_back(t.second); p[i] = t; } for (int i = 1; i <= mid; i++){ if (p[i].first > 1) q.push({p[i].first-1, p[i].second}); } } }; int l = 1, r = std::min(n ,26); while (l < r){ int mid = (l + r + 1)>>1; if (check(mid)) l = mid; else r = mid - 1; } check(l); std::cout << l << '\n'; for (int i = 0; i < ans.size(); i++){ std::cout << char(ans[i]+'a') ; } std::cout << '\n'; } signed main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2); int t = 1, i; for (i = 0; i < t; i++){ solve(); } return 0; }
P1004 [NOIP 2000 提高组] 方格取数
绿色
思路:四维DP
首先观察到此题的数据范围非常(!)小,所以优先考虑爆搜,爆搜有两种,一种是dfs和bfs,还有一种就是DP。我们选择DP的解法,同时处理两次行程能得到的总的最大值
:表示第一次走到 i 和 j ,第二次走到 k 和 l 能得到的最大值。
评述
可惜思考的时候没有想到DP,比较傻×了。
代码
#include<cstdio> #include<iostream> using namespace std; const int N=11; int dp[N][N][N][N]; int a[N][N]; int n,x,y,z; int main() { scanf("%d",&n); for(;;) { scanf("%d%d%d",&x,&y,&z); if(x==y&&y==z&&z==0) { break; } else { a[x][y]=z; } } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { for(int k=1;k<=n;k++) { for(int l=1;l<=n;l++) { dp[i][j][k][l]=max(max(dp[i-1][j][k-1][l],dp[i-1][j][k][l-1]),max(dp[i][j-1][k-1][l],dp[i][j-1][k][l-1]))+a[i][j]+a[k][l]; if(i==k&&l==j)dp[i][j][k][l]-=a[i][j];//注意判断这个点走过几次并处理 } } } } printf("%d",dp[n][n][n][n]); return 0; }
P1005 [NOIP 2007 提高组] 矩阵取数游戏
绿色
思路:区间DP
- 求n行最大得分和,每一行取数又不会影响到其他行,那么只要确保每一行得分最大,管好自家孩子就行了。(这个在动规中叫最优子结构)
- 每次取数是在边缘取,那么每次取数完剩下来的元素一定是在一个完整的一个区间中,又是求最优解,区间DP应运而生。
评述
想了一下DP结果马上被自己否决了,理由是线性DP都是沿着一个方向,这题一会取左边一会取右边肯定不能用线性DP。但是这不恰好是区间DP的主场吗?人傻了
代码
#include <bits/stdc++.h> using namespace std; const int MAXN=81; inline void input(__int128 &s) { s=0; char c=' '; while(c>'9'||c<'0') c=getchar(); while(c>='0'&&c<='9') { s=s*10+c-'0'; c=getchar(); } } inline void output(__int128 x) { if(x>9) output(x/10); putchar(x%10+'0'); } int n, m; __int128 game[MAXN][MAXN]; __int128 f[MAXN][MAXN]; __int128 solve(__int128 a[]) { memset(f,0,sizeof(f)); for(int len=0;len<=m;++len) for(int i=1;i+len<=m;++i) f[i][i+len]=max(2*f[i+1][i+len]+2*a[i],2*f[i][i+len-1]+2*a[i+len]); return f[1][m]; } __int128 ans=0; int main() { cin>>n>>m; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) input(game[i][j]); for(int i=1;i<=n;i++) ans+=solve(game[i]); output(ans); return 0; }
本文作者:califeee
本文链接:https://www.cnblogs.com/califeee/p/18744972
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步