线性(普通)DP题单
题单链接
https://vjudge.net/article/2605
CodeForces-191A Dynasty Puzzles
Codeforces Round #121 (Div. 1)
题意
给出 n 个小写字母组成的字符串。
- 两个字符串如果前者的最后一个字母与后者的首字母相同,那么两者可以连接;
- 还要求最后得到的字符串的首尾字母也要相同;
求最长的满足要求的字符串的长度是多少。
思路
记 f[x][y] 为从第一个字符串到当前字符串,字母 x 到字母 y 的最长字符串的长度。
最后遍历f[x][x],相加就是答案。
然后问题是如何初始化:
其他数据肯定是负无穷
又因为我们所求的f[x][x]对答案的贡献最小为0,因此这些设为0.
代码
#include <bits/stdc++.h> using namespace std; #define int long long const int N = 5e5 + 10; int dp[36][36]; string s; signed main() { int n; cin >> n; for (int i = 0; i < 30; i++) for (int j = 0; j < 30; j++) dp[i][j] = -0x3f3f3f3f; for (int i = 0; i < 30; i++) dp[i][i] = 0; for (int i = 0; i < n; i++) { cin >> s; int be = s[0] - 'a'; int en = s[s.length() - 1] - 'a'; for (int i = 0; i < 26; i++) { if (dp[i][be] == -0x3f3f3f3f) continue; dp[i][en] = max(dp[i][en], dp[i][be] + (int)s.length()); } } int ans = 0; for (int i = 0; i < 26; i++) ans = max(ans, dp[i][i]); cout << ans << endl; return 0; }
CodeForces-455A Boredom
Codeforces Round #260 (Div. 1)
题意
一组数据,从其中选择一个a[k]删除,同时删除值为a[k]-1和a[k]+1的所有数据。
将a[k]的值加到ans,求最大的ans。
思路
设f[i-1]为从1到i-1可以得到的最大ans,则f[i]只取决于f[i-1]。
状态转移方程为:f[i]=max(f[i-1], f[i-2]+i*cnt[i])
代码1 for循环
#include <bits/stdc++.h> using namespace std; #define int long long const int N = 1e5 + 10; int f[N]; int n; int a[N]; set<int> st; map<int,int> mp; signed main() { cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; st.insert(a[i]); mp[a[i]]++; } int sum=0; int pre=0; int maxnn=*st.rbegin(); for(int i=1;i<=maxnn;i++){ if(i==1) f[i]=mp[i]; else f[i] = max(f[i - 1], f[i - 2] +i * mp[i]); } cout << sum+f[maxnn] << endl; return 0; }
代码2 set
使用set处理,需要考虑每段的转移
#include <bits/stdc++.h> using namespace std; #define int long long const int N = 1e5 + 10; int f[N]; int n; int a[N]; set<int> st; map<int,int> mp; signed main() { cin>>n; for(int i=1;i<=n;i++) { cin>>a[i]; st.insert(a[i]); mp[a[i]]++; } int sum=0; int pre=0; int preid; for(int i:st) { if(i==1) f[i]=mp[i]; else { if(f[i-2]==0) f[i-2]=pre;//cout<<pre<<"-->"<<i<<endl; f[i] = max(f[i - 1], f[i - 2] + i * mp[i]); } if(mp[i+1]==0) pre=f[i]; preid=i; } cout << f[*st.rbegin()]<<endl; return 0; }
CodeForces-1061C Multiplicity
Codeforces Round #523 (Div. 2)
题意
给定一个长度为 n 序列 ,现在取该序列的一个子序列 ,其对于任意的 满足,求 序列的个数
思路
容易想到一个 的 dp ,状态为 dp [ i ] [ j ] 表示用 a 序列的前 i 个个数构成了一个长为 j 的序列 b ,这个有转移方程
然后考虑优化时间:
因为数最大是1e6,101001000=1e6所以每个数的因子数量不可能超过1000。
所以我们可以提前 暴力预处理出来每个数的所有因子,复杂度:
然后直接循环每个a[i]的因子,这样复杂度对多不超过
注意一点:不能直接使用滚动数组
因为使用滚动数组时,如果上一轮的信息没有被更新,那么信息就有可能丢失。
原文链接:https://blog.csdn.net/qq_39641976/article/details/117431977
代码
#include <bits/stdc++.h> using namespace std; #define int long long const int N = 1e6 + 10; const int mod = 1e9+7; int dp[N]; int n; int a[N]; vector<int> vec[N]; // set<int> st[N]; signed main() { cin>>n; for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); // cin>>a[i]; int x=a[i]; for(int j=1;j<=sqrt(x);j++){ if(x%j==0){ vec[i].push_back(j); if(x!=j*j)vec[i].push_back(x/j); } } sort(vec[i].begin(),vec[i].end()); } dp[0]=1; for(int i=1;i<=n;i++){ for(int j=vec[i].size()-1;j>=0;j--){ int it=vec[i][j]; // cout<<it<<" "<<i<<endl; dp[it]=(dp[it]+dp[it-1])%mod; } } int ans=0; for(int i=1;i<=n;i++) ans=(ans+dp[i])%mod; printf("%lld\n",ans); return 0; }
4 CodeForces-1110D
Jongmah
3102
Codeforces Global Round 1
5 CodeForces-1312E
Array Shrinking
4844
Educational Codeforces Round 83 (Rated for Div. 2)
6 CodeForces-245H
Queries for Number of Palindromes
4856
CROC-MBTU 2012, Elimination Round (ACM-ICPC)
本文作者:kingwzun
本文链接:https://www.cnblogs.com/kingwz/p/16850405.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步