寒假训练——第三周线性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;
}

相关文章

学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习...
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面...
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生...
Can’t connect to local MySQL server through socket \'/v...
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 ...
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服...