problem 248G
describe
给定一个 1 ×n 的地图,在里面玩 2048,每次可以合并相邻两个(数值范围 1∼40),问序列中出现的最大数字的值最大是多少。注意合并后的数值并非加倍而是 +1,例如 2 与 2 合并后的数值为 3
solution
首先当两个区间相等时,才能进行区间合并得到最大值。 当区间长度为一时,区间内的最大值等于区间本身,即dp[i][i]=a[i];
code
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 250;
int f[N][N];
int main() {
int n, ans = 0;
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", f[i] + i);
ans = max(ans, f[i][i]);
}
for(int len = 2; len <= n; len++)
for(int l = 1; l +len -1 <= n; l++) {
int r = l + len - 1;
for(int k = l; k < r; k++)
if(f[l][k] == f[k + 1][r] && f[l][k]) {
f[l][r] = max(f[l][r], f[l][k] + 1);
ans = max(ans, f[l][r]);
}
}
printf("%d\n", ans);
return 0;
}
problem 涂色
describe
假设你有一条长度为 5 的木板,初始时没有涂过任何颜色。你希望把它的 5 个单位长度分别涂上红、绿、蓝、绿、红色,用一个长度为 5 的字符串表示这个目标:RGBGR
每次你可以把一段连续的木板涂成一个给定的颜色,后涂的颜色覆盖先涂的颜色。例如第一次把木板涂成 RRRRR,第二次涂RGGGR,第三次涂成 RGBGR,达到目标。
用尽量少的涂色次数达到目标。
solution
dp[i][j] 表示在[i,j]区间内的最小次数
首先,当区间len1,即ij时,次数最小为1。当len!=1,即i!=j 时,判断最左边和最右边的元素是否一致,
code
#include <iostream>
#include <cstring>
#define INF 0x3f3f3f
using namespace std;
int N;
int f[52][52];
string a;
int main(){
cin>>a;
N = a.size();
memset(f,INF,sizeof(f));
for(int i = 1;i <= N;i++){
f[i][i] = 1;
}
for(int len = 2; len <= N; len++){
for(int i = 1; i <= N - len + 1; i++){
int head = i, tail = i + len - 1;
if(a[head-1] == a[tail-1]){
f[head][tail]=min(f[head + 1][tail],f[head][tail-1]);
continue;
}
for(int k = head; k <= tail; k++){
f[head][tail]=min(f[head][k] + f[k+1][tail],f[head][tail]);
}
}
}
cout<<f[1][N];
}
problem 合唱队
describe
定合唱队一共 n 个人,第 i 个人的身高为 hi 米(1000≤hi ≤2000),并已知任何两个人的身高都不同。假定最终排出的队形是 A 个人站成一排,为了简化问题,小 A 想出了如下排队的方式:他让所有的人先按任意顺序站成一个初始队形,然后从左到右按以下原则依次将每个人插入最终棑排出的队形中:
第一个人直接插入空的当前队形中。
对从第二个人开始的每个人,如果他比前面那个人高(h 较大),那么将他插入当前队形的最右边。如果他比前面那个人矮(h 较小),那么将他插入当前队形的最左边。
当 n 个人全部插入当前队形后便获得最终排出的队形。
solution
首先大致分为四种情况,在首项的左边和右边,在尾项的左边和右边。 通过判断 a[i],a[+1],a[j},a[j-1] 的关系,书写状态转移方程。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1005, mod = 19650827;
int n, a[MAXN];
int f[MAXN][MAXN], g[MAXN][MAXN];
int sovle()
{
for(int i=0;i<n;i++) //初始值,只有一个人的区间只有1种情况
f[i][i]=1;
for(int len=1;len<n;len++)
for(int i=0;i+len<n;i++)
{
f[i][i+len]=( f[i+1][i+len]*(a[i]<a[i+1]) +
g[i+1][i+len]*(a[i]<a[i+len]) )%mod;
g[i][i+len]=( f[i][i+len-1]*(a[i+len]>a[i]) +
g[i][i+len-1]*(a[i+len]>a[i+len-1]) )%mod;
}
return (f[0][n-1]+g[0][n-1])%mod;
}
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
cout<<sovle()<<endl;
return 0;
}