寒假训练——第三周线性DP

A - 数塔问题

A - 数塔问题
思路:

  • 数字三角形模型

代码如下:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>

#define fast ios::sync_with_stdio(false), cin.tie(nullptr); cout.tie(nullptr)

#define x first
#define y second
#define int long long

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const LL LL_INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-9;

const int N = 210, M = 2e5 + 10;

const int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};

int T, cases;
int n, m;
int f[N][N];

void solve()
{
    cin >> n;
    
    memset(f, 0, sizeof f);
    
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= i; j ++ )
            cin >> f[i][j];
            
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= i; j ++ )  
            f[i][j] += max(f[i - 1][j - 1], f[i - 1][j]);
    
    int res = -1;
    for (int i = 1; i <= n; i ++ )  
        res = max(res, f[n][i]);
        
    cout << res << endl;
    
    return;
}

signed main()
{
    //fast;
    T = 1;
    //cin >> T;
    
    while(T -- )
        solve();
    
    return 0;
}

B - 最长上升子序列

B - 最长上升子序列

思路:

  • 最长上升子序列模型( l o n g e s t   i n c r e a s i n g   s e q u e n c e longest~increasing~sequence longest increasing sequence ),又称 L I S LIS LIS 模型

代码如下:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>

#define fast ios::sync_with_stdio(false), cin.tie(nullptr); cout.tie(nullptr)

#define x first
#define y second
#define int long long

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const LL LL_INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-9;

const int N = 2100, M = 2e5 + 10;

const int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};

int T, cases;
int n, m;
int a[N];
int f[N];

void solve()
{
    cin >> n;
    
    for (int i = 1; i <= n; i ++ )  
        cin >> a[i];
    
    for (int i = 1; i <= n; i ++ )
    {
        f[i] = 1;
        for (int j = 1; j < i; j ++ )
            if(a[j] < a[i]) f[i] = max(f[i], f[j] + 1);
    }
    
    int res = 0;
    for (int i = 1; i <= n; i ++ )
        res = max(res, f[i]);
        
    cout << res << endl;
    
    return;
}

signed main()
{
    //fast;
    T = 1;
    //cin >> T;
    
    while(T -- )
        solve();
    
    return 0;
}

C - 最长公共子序列 ( L C S LCS LCS ): O ( n l o g n ) O(nlogn) O(nlogn)做法

全称:( l o n g e s t   c o m m o n   s e q u e n c e longest~common~sequence longest common sequence )

C - 最长公共子序列

前提:

  • 最长公共子序列至少有一个序列元素不重复

思路:

  • 最长公共子序列( 转化为 最长上升子序列
  • 按照 最长上升子序列的优化方案一 (点此链接看详细证明):贪心 + 二分 优化为 O ( n l o g n ) O(nlogn) O(nlogn)

具体步骤:

  • 将元素不重复的序列的元素映射到其下标
  • 在第二个序列中找到每个元素在第一个序列中的下标,构造新序列,
  • 我们要求的结果即为新序列的 最长上升子序列( L I S LIS LIS )

证明:

  • 找 最长公共子序列 只需维护数据的相对位置关系即可

举例:

  • input:
    5 
    3 2 1 4 5
    1 2 3 4 5
    
  • output:
    3
    
  • 如图:

    在这里插入图片描述

代码如下:

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 1e6 + 10;

int n;
int id[N], q[N];

int main()
{  
    scanf("%d", &n);
    
    memset(id, -1, sizeof id);
    
    for (int i = 0; i < n; i ++ )
    {
        int x;
        scanf("%d", &x);
        id[x] = i;
    }
    
    int len = 0;
    q[0] = -1; 
    // 位置序列中最小值为 0 ,所以设置一个比最小值还小的值 -1 作为哨兵,
    // 防止数组越界,保证了在二分的时候一定能找到结果
    
    for (int i = 0; i < n; i ++ )
    {
        int x;
        scanf("%d", &x);
        if(id[x] == -1) continue;
        int k = id[x];
        int l = 0, r = len;
        while(l < r)
        {
            int mid = l + r + 1 >> 1;
            if(q[mid] < k) l = mid;
            else r = mid - 1;
        }
        
        q[r + 1] = k;
        len = max(len, r + 1);
    }
    
    printf("%d\n", len);
    
    return 0;
}

D - 摘花生

D - 摘花生

思路:

  • 模拟,,水题

代码如下:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <bitset>
#include <vector>
#include <queue>
#include <cmath>
#include <map>
#include <set>

#define fast ios::sync_with_stdio(false), cin.tie(nullptr); cout.tie(nullptr)

#define x first
#define y second
#define int long long

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const LL LL_INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-9;

const int N = 110, M = 1e5 + 10;

const int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};

int T, cases;
int n, m, times;

struct Points
{
    int x, y, w;
    bool operator < (const Points &W)const
    {
        return W.w < w;
    }
}g[M];

int idx;

void solve()
{
    memset(g, 0, sizeof g);
    idx = 0;
    
    cin >> n >> m >> times;
    
    int x;
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ )
        {
            cin >> x;
            if(x > 0) g[idx ++ ] = {i, j, x};
        }
        
    sort(g, g + idx);
    
    int res = 0;
    int lastx = 0, lasty;
    for (int i = 0; i < idx; i ++ )
    {
        if(!i) lasty = g[i].y;
        
        int t = abs(g[i].x - lastx) + abs(g[i].y - lasty);
        
        if(times >= g[i].x + t + 1)
        {
            times -= t + 1;
            res += g[i].w;
            lastx = g[i].x, lasty = g[i].y;
        }
        else break;
    }
    
    cout << res << endl;
    
    return;
}

signed main()
{
    //fast;
    T = 1;
    cin >> T;
    
    while(T -- )
        solve();
    
    return 0;
}

E - Boxes of Chocolates Again

E - Boxes of Chocolates Again

思路:

  • 完全背包求方案数 + 高精度加法

问: 高精度用 v e c t o r vector vector 慢的一批,不管了(这题没啥意思,,)思路就是这样,有高人救一下否 ? ? ?

答: 高精度压位即可, i n t int int类型 只存 0~9 的一位数实在是浪费,并且速度还慢, i n t int int 类型习惯压 4 4 4 8 8 8 位,最多可以压 9 9 9 位。

注: 想学习高精度压位的,参考此博客:【算法专题】高精度之压位
写的确实不错啊,膜拜 dalao ! ! !

代码如下:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <bitset>
#include <vector>
#include <queue>
#include <cmath>
#include <map>
#include <set>

#define fast ios::sync_with_stdio(false), cin.tie(nullptr); cout.tie(nullptr)

#define x first
#define y second
#define int long long

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const LL LL_INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-9;

const int N = 5500, M = N * 2;
const int YB = 8, YM = 1e8;

const int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};

int T, cases;
int n, m, times;

vector<int> f[N];

vector<int> add(vector<int> &A, vector<int> &B)
{
    if(A.size() < B.size()) return add(B, A);
    
    vector<int> C;
    int t = 0;
    for (int i = 0; i < A.size(); i ++ )
    {
        t += A[i];
        if(i < B.size()) t += B[i];
        C.push_back(t % YM);
        t /= YM;
    }
    
    if(t) C.push_back(t);
    
    return C;
}

void print(vector<int> f)
{
    printf("%d", f.back());
    for (int i = f.size() - 2; i >= 0; i -- )
        printf("%08d", f[i]);
    printf("\n");
}

void init()
{
    f[0].push_back(1);
    for (int i = 1; i <= 5010; i ++ )
        for (int j = i; j <= 5010; j ++ )
            f[j] = add(f[j], f[j - i]);
    
    return;
}

void solve()
{
    print(f[n]);
}

signed main()
{
    //fast;
    T = 1;
    //cin >> T;
    
    init();
    
    while(cin >> n)
        solve();
    
    return 0;
}

F - Road Optimization

F - Road Optimization

思路:

  • 在这里插入图片描述

  • 直接枚举 f [ i ] [ j ] f[i][j] f[i][j] 是从哪一次转移过来的即可

代码如下:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <bitset>
#include <vector>
#include <queue>
#include <cmath>
#include <map>
#include <set>

#define fast ios::sync_with_stdio(false), cin.tie(nullptr); cout.tie(nullptr)

#define x first
#define y second
#define int long long

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const LL LL_INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-9;

const int N = 510, M = N * 2;

const int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};

int T, cases;
int n, m, allow;
int dist[N];
int speed[N];
int f[N][N];

void solve()
{
    cin >> n >> m >> allow;
    
    for (int i = 1; i <= n; i ++ )
        cin >> dist[i];
    for (int i = 1; i <= n; i ++ )
        cin >> speed[i];
    
    dist[ ++ n] = m;
    
    memset(f, 0x3f, sizeof f);
    f[1][1] = 0;
    
    for (int i = 2; i <= n; i ++ )
        for (int j = 1; j <= i; j ++ )
            for (int k = 1; k < i; k ++ )
                f[i][j] = min(f[i][j], f[k][j - 1] + (dist[i] - dist[k]) * speed[k]);
                
    int res = INF;
    for (int i = 0; i <= allow; i ++ ) res = min(res, f[n][n - i]);

    cout << res << endl;
}

signed main()
{
    //fast;
    T = 1;
    //cin >> T;
    
    while(T -- )
        solve();
    
    return 0;
}

G - Hasan and his lazy students

G - Hasan and his lazy students

思路:

  • 最长上升子序列求方案数

代码如下:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <bitset>
#include <vector>
#include <queue>
#include <cmath>
#include <map>
#include <set>

#define fast ios::sync_with_stdio(false), cin.tie(nullptr); cout.tie(nullptr)

#define x first
#define y second
#define int long long

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const LL LL_INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-9;

const int N = 2010, M = N * 2;

const int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};

int T, cases;
int n, m, allow;
int a[N];
int f[N];
int g[N];

void solve()
{
    cin >> n;
    for (int i = 1; i <= n; i ++ )
        cin >> a[i];
    
    memset(f, 0, sizeof f);
    memset(g, 0, sizeof g);
    
    for (int i = 1; i <= n; i ++ )
    {
        f[i] = 1;
        for (int j = 1; j < i; j ++ )
            if(a[j] < a[i]) f[i] = max(f[i], f[j] + 1);
        
        g[i] = 0;
        for (int j = 1; j < i; j ++ )
            if(a[j] < a[i] && f[i] == f[j] + 1)
                g[i] =(g[i] + g[j]) % mod;
        if(!g[i]) g[i] = 1;
    }
    
    int res = 0;
    for (int i = 1; i <= n; i ++ )  res = max(res, f[i]);
    
    int num = 0;
    for (int i = 1; i <= n; i ++ )
        if(f[i] == res) num = (num + g[i]) % mod;
    
    cout << res << " " << num << endl;
    
    return;
}

signed main()
{
    fast;
    T = 1;
    cin >> T;
    
    while(T -- )
        solve();
    
    return 0;
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340