codeforces 567F Mausoleum (dp)

l i n k link link:添加链接描述


f l , r f_{l,r} fl,r 表示左右分别放到 l 、 r l、r lr 的位置每次转移的时候考虑一下限制就行了。

如果用 f i , j f_{i,j} fi,j 表示用了前 i i i 个数字放到第 j j j 也等价,可以用 i , j i,j i,j 推出 l , r l,r l,r 细节很多的一道题

#include <bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define fr first
#define se second
#define ll long long
#define gg {flag = false;break;}
int rd() {
    int sum = 0;char c = getchar();bool flag = true;
    while(c < '0' || c > '9') {if(c == '-') flag = false;c = getchar();}
    while(c >= '0' && c <= '9') sum = sum * 10 + c - 48,c = getchar();	
    if(flag) return sum;
    else return -sum;
}
int n,q;
ll f[100][100];
pair<pair<int,int>,int>h[110]; 
// 1:<  2:<=  3:=  4:> 5:>=
void pre() {
	char c;
	int i = 1;
	while(i <= q) {
		h[i].fr.fr = rd();
		c = getchar(); while(c == ' ') c = getchar();
		if(c == '<') h[i].se = 1;
		if(c == '=') h[i].se = 3;
		if(c == '>') h[i].se = 4;
		c = getchar(); if(c == '=') h[i].se++;
		h[i].fr.se = rd();
		
		if(h[i].fr.fr > h[i].fr.se) {
			swap( h[i].fr.fr , h[i].fr.se );
			if(h[i].se == 1 || h[i].se == 2) h[i].se += 3;
			else if(h[i].se == 4 || h[i].se == 5) h[i].se -= 3;
		}
		if(h[i].fr.fr == h[i].fr.se) 
		    if(h[i].se == 1 || h[i].se == 4) {printf("0\n");exit(0);}
		    else q--;
		else i++;
	}
	sort(h+1,h+q+1);
}
void work() {
	ll ans = 0;
	f[0][2*n+1] = 1;
	rep(i,0,n-1) rep(l,0,2*i) {
		int r = 2*n+1-(2*i-l); bool flag = true;
		rep(k,1,q) if(h[k].fr.fr == l+1){
			if(h[k].fr.se > r-1) {if(h[k].se <= 3) gg;}
			else if(h[k].fr.se == r-1) {if(h[k].se == 1 || h[k].se == 4) gg;}
			else if(h[k].se >= 3) gg;
		} 
		if(flag)
		rep(k,1,q) if(h[k].fr.fr == r-1) if(h[k].se <= 3) gg;
		if(flag && i != n-1) f[l+1][r-1] += f[l][r];
		
		flag = true;
		rep(k,1,q) if(h[k].fr.fr == l+1) {
			if(h[k].fr.se == l+2) {if(h[k].se == 1 || h[k].se == 4) gg;}
			else if(h[k].fr.se >= r) {if(h[k].se <= 3) gg;}
			else {if(h[k].se >= 3)gg;}
	    }
	    if(flag) rep(k,1,q) if(h[k].fr.fr == l+2) {
	    	if(h[k].fr.se >= r) {if(h[k].se <= 3)gg;}
	    	else {if(h[k].se >= 3) gg;}
		}
		if(flag) f[l+2][r] += f[l][r];
		
		flag = true;
		rep(k,1,q) if(h[k].fr.fr == r-2) {
			if(h[k].fr.se == r-1) {if(h[k].se == 1 || h[k].se == 4) gg; }
			else if(h[k].se <= 3) gg;
		}
		else if(h[k].fr.fr == r-1) if(h[k].se <= 3) gg;
		if(i != n-1 && flag) f[l][r-2] += f[l][r];
    }
	rep(i,0,2*n) ans += f[i][i+1];
	printf("%lld\n",ans);
}
int main() {
    n = rd(); q = rd();
    pre();
    work(); 
	return 0; 
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
区间DP是一种动态规划的方法,用于解决区间范围内的问题。在Codeforces竞赛中,区间DP经常被用于解决一些复杂的字符串或序列相关的问题。 在区间DP中,dp[i][j]表示第一个序列前i个元素和第二个序列前j个元素的最优解。具体的转移方程会根据具体的问题而变化,但是通常会涉及到比较两个序列的元素是否相等,然后根据不同的情况进行状态转移。 对于区间长度为1的情况,可以先进行初始化,然后再通过枚举区间长度和区间左端点,计算出dp[i][j]的值。 以下是一个示例代码,展示了如何使用区间DP来解决一个字符串匹配的问题: #include <cstdio> #include <cstring> #include <string> #include <iostream> #include <algorithm> using namespace std; const int maxn=510; const int inf=0x3f3f3f3f; int n,dp[maxn][maxn]; char s[maxn]; int main() { scanf("%d", &n); scanf("%s", s + 1); for(int i = 1; i <= n; i++) dp[i][i] = 1; for(int i = 1; i <= n; i++) { if(s[i] == s[i - 1]) dp[i][i - 1] = 1; else dp[i][i - 1] = 2; } for(int len = 3; len <= n; len++) { int r; for(int l = 1; l + len - 1 <= n; l++) { r = l + len - 1; dp[l][r] = inf; if(s[l] == s[r]) dp[l][r] = min(dp[l + 1][r], dp[l][r - 1]); else { for(int k = l; k <= r; k++) { dp[l][r] = min(dp[l][r], dp[l][k] + dp[k + 1][r]); } } } } printf("%d\n", dp[n]); return 0; } 希望这个例子能帮助你理解区间DP的基本思想和应用方法。如果你还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值