Nefu区间dp,ACM暑期培训

                                A - 能量项链

题目描述

在 Mars 星球上,每个 Mars 人都随身佩带着一串能量项链。在项链上有 N 颗能量珠。能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数。并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定等于后一颗珠子的头标记。因为只有这样,通过吸盘(吸盘是 Mars 人吸收能量的一种器官)的作用,这两颗珠子才能聚合成一颗珠子,同时释放出可以被吸盘吸收的能量。如果前一颗能量珠的头标记为 m,尾标记为 r,后一颗能量珠的头标记为 r,尾标记为 n,则聚合后释放的能量为 m×r×n(Mars 单位),新产生的珠子的头标记为 m,尾标记为 n。

需要时,Mars 人就用吸盘夹住相邻的两颗珠子,通过聚合得到能量,直到项链上只剩下一颗珠子为止。显然,不同的聚合顺序得到的总能量是不同的,请你设计一个聚合顺序,使一串项链释放出的总能量最大。

例如:设 N=4,4 颗珠子的头标记与尾标记依次为 (2,3)(3,5)(5,10)(10,2).我们用记号 ⊕ 表示两颗珠子的聚合操作,(j⊕k) 表示第 j,k 两颗珠子聚合后所释放的能量。则第 4,1 两颗珠子聚合后释放的能量为:

(4⊕1)=10×2×3=60。

这一串项链可以得到最优值的一个聚合顺序所释放的总能量为:

(((4⊕1)⊕2)⊕3)=10×2×3+10×3×5+10×5×10=710。

输入格式

第一行是一个正整数 N(4≤N≤100),表示项链上珠子的个数。第二行是 N 个用空格隔开的正整数,所有的数均不超过1000。第 i 个数为第 i 颗珠子的头标记(1≤i≤N),当 i<N 时,第 i 颗珠子的尾标记应该等于第i+1 颗珠子的头标记。第 N 颗珠子的尾标记应该等于第 11 颗珠子的头标记。

至于珠子的顺序,你可以这样确定:将项链放到桌面上,不要出现交叉,随意指定第一颗珠子,然后按顺时针方向确定其他珠子的顺序。

输出格式

一个正整数 E(E≤2.1×109),为一个最优聚合顺序所释放的总能量。

输入输出样例

输入 #1复制

4
2 3 5 10

输出 #1复制

710

说明/提示

NOIP 2006 提高组 第一题

解析:区间dp

本题的数据是一个环,解决这的办法是将数组加长,两倍的输出长度,前一段和后一段的数据一样,每次只处理长度位n的数据,然后就没什么难点了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long LL;
const int N = 200 + 5;
const int INF = 1e9;
int n;
int sum[N], dp[N][N];


int main() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		scanf("%d", &sum[i]);
	}
	for (int i = 1; i <= n; i++) {
		sum[i + n] = sum[i];
	}
	for (int len = 2; len <= n; len++) {
		for (int l = 1; l + len - 1 <= 2*n; l++) {
			int r = l + len;
			for (int k = l + 1; k < r; k++) {
				dp[l][r] = max(dp[l][r], dp[l][k] + dp[k][r] + sum[l] * sum[k] * sum[r]);
			}
		}
	}

	int mx = 0;
	for (int l = 1; l <= n; l++) {
		mx = max(mx, dp[l][l + n]);
	}
	cout << mx << endl;
	return 0;
}

                                        F - 合唱队

题目描述

为了在即将到来的晚会上有更好的演出效果,作为 AAA 合唱队负责人的小 A 需要将合唱队的人根据他们的身高排出一个队形。假定合唱队一共 n 个人,第 i 个人的身高为 hi​ 米(1000≤hi​≤2000),并已知任何两个人的身高都不同。假定最终排出的队形是 A 个人站成一排,为了简化问题,小 A 想出了如下排队的方式:他让所有的人先按任意顺序站成一个初始队形,然后从左到右按以下原则依次将每个人插入最终棑排出的队形中:

  • 第一个人直接插入空的当前队形中。

  • 对从第二个人开始的每个人,如果他比前面那个人高(ℎh 较大),那么将他插入当前队形的最右边。如果他比前面那个人矮(ℎh 较小),那么将他插入当前队形的最左边。

当 n 个人全部插入当前队形后便获得最终排出的队形。

例如,有 66 个人站成一个初始队形,身高依次为 1850,1900,1700,1650,1800,17501850,1900,1700,1650,1800,1750,
那么小 A 会按以下步骤获得最终排出的队形:

  • 18501850。

  • 1850,19001850,1900,因为 1900>1850

  • 1700,1850,19001700,1850,1900,因为 1700<1900

  • 1650,1700,1850,19001650,1700,1850,1900,因为 1650<1700

  • 1650,1700,1850,1900,18001650,1700,1850,1900,1800,因为 1800>1650

  • 1750,1650,1700,1850,1900,18001750,1650,1700,1850,1900,1800,因为 1750<1800

因此,最终排出的队形是 1750,1650,1700,1850,1900,1800。

小 A 心中有一个理想队形,他想知道多少种初始队形可以获得理想的队形。

请求出答案对 19650827取模的值。

输入格式

第一行一个整数 n。
第二行 n 个整数,表示小 A 心中的理想队形。

输出格式

输出一行一个整数,表示答案  mod 19650827 的值。

输入输出样例

输入 #1复制

4
1701 1702 1703 1704

输出 #1复制

8

说明/提示

对于 30%30% 的数据,n≤100。
对于 100%100% 的数据,n≤1000,1000≤hi​≤2000。

解析:区间dp,三维

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long LL;
const int N = 1000 + 5;
int a[N], dp[N][N][2];
int n;


int main() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
	}
	for (int i = 1; i <= n; i++) {
		dp[i][i][0] = 1;
		/*dp[i][i][1] = 1;*/
	}

	for (int i = n; i >= 1; i--) {
		for (int j = i + 1; j <= n; j++) {
			if (a[i + 1] > a[i]) {
				dp[i][j][0] += dp[i + 1][j][0];
			}
			if (a[j] > a[i] /*&& i + 1 != j*/) {
				dp[i][j][0] += dp[i + 1][j][1];
			}
			if (a[j - 1] < a[j]) {
				dp[i][j][1] += dp[i][j - 1][1];
			}
			if (a[i] < a[j] /*&& j - 1 != i*/) {
				dp[i][j][1] += dp[i][j - 1][0];
			}
			dp[i][j][0] %= 19650827;
			dp[i][j][1] %= 19650827;
		}
	}
	cout << (dp[1][n][0] + dp[1][n][1]) % 19650827 << endl;
	return 0;
}

                                   

                                        H - 玩具取名

P4290 [HAOI2008] 玩具取名 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

Description

某人有一套玩具,并想法给玩具命名。首先他选择WING四个字母中的任意一个字母作为玩具的基本名字。然后他会根据自己的喜好,将名字中任意一个字母用“WING”中任意两个字母代替,使得自己的名字能够扩充得很长。

现在,他想请你猜猜某一个很长的名字,最初可能是由哪几个字母变形过来的。

Input

第一行四个整数W、I、N、G。表示每一个字母能由几种两个字母所替代。

接下来W行,每行两个字母,表示W可以用这两个字母替代。

接下来I行,每行两个字母,表示I可以用这两个字母替代。

接下来N行,每行两个字母,表示N可以用这两个字母替代。

接下来G行,每行两个字母,表示G可以用这两个字母替代。

最后一行一个长度不超过Len的字符串。表示这个玩具的名字。

Output

一行字符串,该名字可能由哪些字母变形而得到。(按照WING的顺序输出)

如果给的名字不能由任何一个字母变形而得到则输出“The name is wrong!”

Sample 1

InputcopyOutputcopy
1 1 1 1
II
WW
WW
IG
IIII
IN

Hint

30%数据满足Len<=20,W、I、N、G<=6

100%数据满足Len<=200,W、I、N、G<=16

解析:区间dp,三维数组

[HAOI2008]玩具取名_牛客博客 (nowcoder.net)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long LL;
const int N = 300+7;
int p[5];
int a[N];
int can[N][N][N],dp[N][N][N];
char s[N];

int main() {
	a['W'] = 1;
	a['I'] = 2;
	a['N'] = 3;
	a['G'] = 4;
	for (int i = 1; i <= 4; i++) {
		cin >> p[i];
	}
	for (int i = 1; i <= 4; i++) {
		char x, y;
		for (int j = 1; j <= p[i]; j++) {
			cin >> x >> y;
			can[i][a[x]][a[y]] = 1;
		}
	}
	cin >> (s + 1);
	int n = strlen(s + 1);
	for (int i = 1; i <= n; i++)
		dp[i][i][a[s[i]]] = 1;
	for (int len = 2; len <= n; len++) {
		for (int i = 1; i <= n; i++) {
			int j = i + len - 1;
			if (j > n)break;
			for (int k =i; k < j; k++) {
				for (int z = 1; z <= 4; z++) {
					for (int z1 = 1; z1 <= 4; z1++) {
						for (int z2 = 1; z2 <= 4; z2++) {
							if (can[z][z1][z2] && dp[i][k][z1] && dp[k + 1][j][z2])
								dp[i][j][z] = 1;
						}
					}
				}
			}
		}
	}
	bool flag = false;
	if (dp[1][n][1]) { flag = true; printf("W"); }
	if (dp[1][n][2]) { flag = true; printf("I"); }
	if (dp[1][n][3]) { flag = true; printf("N"); }
	if (dp[1][n][4]) { flag = true; printf("G"); }
	if (!flag) printf("The name is wrong!");
	return 0;
}

posted @ 2023-07-31 11:16  Landnig_on_Mars  阅读(5)  评论(0编辑  收藏  举报  来源