DP精选

非常棒的DP

F. Igor and Mountain

rating:1800

https://codeforces.com/problemset/problem/2091/F

评述:

并不能说此题很难,如果能充分理解题意的话就是一道中等难度的DP

代码

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;

#if !defined(ONLINE_JUDGE) && defined(LOCAL)
#include "helper.h"
#else
#define dbg(...) ;
#define local_go_m(x) int c;cin>>c;while(c--)x()
#endif

template<class T>
constexpr T power(T a, i64 b) {
    T res = 1;
    for (; b != 0; b /= 2, a *= a) {
        if (b & 1) {
            res *= a;
        }
    }
    return res;
}

template<int M>
struct ModInt {
public:
    constexpr ModInt() : x(0) {}

    template<std::signed_integral T>
    constexpr ModInt(T x_) {
        T v = x_ % M;
        if (v < 0) {
            v += M;
        }
        x = v;
    }

    constexpr int val() const {
        return x;
    }

    constexpr ModInt operator-() const {
        ModInt res;
        res.x = (x == 0 ? 0 : M - x);
        return res;
    }

    constexpr ModInt inv() const {
        return power(*this, M - 2);
    }

    constexpr ModInt &operator*=(const ModInt &rhs) &{
        x = i64(x) * rhs.val() % M;
        return *this;
    }

    constexpr ModInt &operator+=(const ModInt &rhs) &{
        x += rhs.val();
        if (x >= M) {
            x -= M;
        }
        return *this;
    }

    constexpr ModInt &operator-=(const ModInt &rhs) &{
        x -= rhs.val();
        if (x < 0) {
            x += M;
        }
        return *this;
    }

    constexpr ModInt &operator/=(const ModInt &rhs) &{
        return *this *= rhs.inv();
    }

    friend constexpr ModInt operator*(ModInt lhs, const ModInt &rhs) {
        lhs *= rhs;
        return lhs;
    }

    friend constexpr ModInt operator+(ModInt lhs, const ModInt &rhs) {
        lhs += rhs;
        return lhs;
    }

    friend constexpr ModInt operator-(ModInt lhs, const ModInt &rhs) {
        lhs -= rhs;
        return lhs;
    }

    friend constexpr ModInt operator/(ModInt lhs, const ModInt &rhs) {
        lhs /= rhs;
        return lhs;
    }

    friend constexpr std::istream &operator>>(std::istream &is, ModInt &a) {
        i64 i;
        is >> i;
        a = i;
        return is;
    }

    friend constexpr std::ostream &operator<<(std::ostream &os, const ModInt &a) {
        return os << a.val();
    }

    friend constexpr std::strong_ordering operator<=>(ModInt lhs, ModInt rhs) {
        return lhs.val() <=> rhs.val();
    }

private:
    int x;
};

constexpr int M = 998244353;
using Z = ModInt<M>;

void go() {
    int n,m,d;std::cin>>n>>m>>d;
    std::vector<std::string> a(n);
    for(int i=0;i<n;i++)std::cin>>a[i];
    std::vector f(n,std::vector<Z>(m,0));
    auto merge=[&](int row,int dis)->std::vector<Z>{
        std::vector<Z> c(m,0);
        int l=0,r=1;
        Z cur=f[row][l];
        for(int i=0;i<m;i++){
            while(r<m&&r-i<=dis)cur+=f[row][r++];
            while(l<m&&i-l>dis)cur-=f[row][l++];
            c[i]=cur;
        }
        return c;
    };
    auto hor=[&](int row)->void{
        auto c=merge(row,d);
        for(int i=0;i<m;i++){
            if(a[row][i]=='X')f[row][i]=c[i];
        }
    };
    for(int j=0;j<m;j++){
        if(a[n-1][j]=='X')f[n-1][j]=1;
    }
    hor(n-1);
    int d2=int(sqrt(i64(d)*d-1));
    for(int i=n-2;i>=0;i--){
        auto c=merge(i+1,d2);
        for(int j=0;j<m;j++){
            if(a[i][j]=='X')f[i][j]=c[j];
        }
        hor(i);
    }
    Z res=0;
    for(int i=0;i<m;i++)res+=f[0][i];
    std::cout<<res<<'\n';
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    local_go_m(go);
    return 0;
}

F - Happy Birthday! 3

rating:2100

https://atcoder.jp/contests/abc400/tasks/abc400_f

思路:区间DP

其实只有两种操作:1是单独修改,2是区间修改。如何考虑区间修改呢?我们在c[k]==c[r]时考虑区间修改的情况。

#include <bits/stdc++.h>

using namespace std;

#define int long long

const int N = 810;

int n, c[N], x[N];
int f[N][N];

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    cin >> n;
    
    for (int i = 1; i <= n; ++ i ) cin >> c[i], c[i + n] = c[i];
    for (int i = 1; i <= n; ++ i ) cin >> x[i];
    
    for (int i = 1; i <= n * 2; ++ i ) {
        f[i][i] = x[c[i]] + 1;
    }
    
    for(int len=2;len<=n;len++){
        for(int l=1;l+len-1<=2*n;l++){
            int r=l+len-1;
            f[l][r]=f[l][r-1]+f[r][r];
            for(int k=l;k<r;k++){
                if(c[k]==c[r])f[l][r]=std::min(f[l][r],f[l][k]+r-k+f[k+1][r-1]);
            }
        }
    }
    int res = 1e18;
    for (int l = 1, r = n; r <= 2 * n; ++ l, ++ r ) res = min(res, f[l][r]);
    cout << res;
    
    return 0;
}

天梯赛L3难度

https://pintia.cn/problem-sets/994805046380707840/exam/problems/type/7?problemSetProblemId=994805054207279104&page=1

评述

练习暴搜和DP+溯源。

代码

#include <bits/stdc++.h>

using pii = std::pair<int,int>;
using u64 = unsigned long long;
using i64 = long long;
const int N = 1e5+5;
namespace ranges = std::ranges;

void solve(){
	int n,m;std::cin>>n>>m;
	std::vector<int> a(n+1);
	for(int i=1;i<=n;i++)std::cin>>a[i];
	std::sort(a.begin()+1,a.end(),std::greater());
	std::vector f(n+1,std::vector<int>(m+1));
	std::vector pre(n+1,std::vector<int>(m+1));
	for(int i=1;i<=n;i++){
		for(int j=0;j<=m;j++){
			f[i][j]=f[i-1][j];
			if(j-a[i]>=0&&f[i][j]<=f[i-1][j-a[i]]+a[i]){
				f[i][j]=f[i-1][j-a[i]]+a[i];
				pre[i][j]=1;
			}
		}
	}
	std::vector<int> ans;
	if(f[n][m]==m){
		int id=n;
		while(m){
			if(pre[id][m]){
				ans.push_back(a[id]);
				m-=a[id];
			}
			id--;
		}
		for(int i=0;i<ans.size();i++){
			if(i!=ans.size()-1)std::cout<<ans[i]<<' ';
			else std::cout<<ans[i];
		}
		std::cout<<'\n';
	}else{
		std::cout<<"No Solution\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;
}
posted @ 2025-04-03 22:05  califeee  阅读(13)  评论(0)    收藏  举报