线性(普通)DP题单

题单链接

https://vjudge.net/article/2605

CodeForces-191A Dynasty Puzzles

Codeforces Round #121 (Div. 1)

题意

给出 n 个小写字母组成的字符串。

  • 两个字符串如果前者的最后一个字母与后者的首字母相同,那么两者可以连接;
  • 还要求最后得到的字符串的首尾字母也要相同;

求最长的满足要求的字符串的长度是多少。

思路

记 f[x][y] 为从第一个字符串到当前字符串,字母 x 到字母 y 的最长字符串的长度。
最后遍历f[x][x],相加就是答案。

转自:https://dilthey.cnblogs.com/

然后问题是如何初始化:
其他数据肯定是负无穷
又因为我们所求的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 序列 \(a\),现在取该序列的一个子序列\(b\) ,其对于任意的 \(b_i\) 满足\(i|b_i\),求 \(b\) 序列的个数

思路

容易想到一个 \(O(n^2)\)的 dp ,状态为 dp [ i ] [ j ] 表示用 a 序列的前 i 个个数构成了一个长为 j 的序列 b ,这个有转移方程
$ dp[i][j]=dp[i-1][j] + dp[i-1][j-1]*[i∣a]$

然后考虑优化时间:
因为数最大是1e6,101001000=1e6所以每个数的因子数量不可能超过1000。
所以我们可以提前 暴力预处理出来每个数的所有因子,复杂度:\(n\sqrt n\)
然后直接循环每个a[i]的因子,这样复杂度对多不超过\(1000*n\)

注意一点:不能直接使用滚动数组
因为使用滚动数组时,如果上一轮的信息没有被更新,那么信息就有可能丢失。
原文链接: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)

posted @ 2022-11-02 11:12  kingwzun  阅读(75)  评论(0编辑  收藏  举报