获取中...

-

Just a minute...

一.最长上升(下降)子序列

https://www.luogu.org/problemnew/show/P1091

https://www.luogu.org/problemnew/show/P1020

P1091:

让每一个人做最中间人,然后分别求到俩边的最长下降子序列

注意要选取中间人为最高的对比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/*-------------------------------------------------------*/

int a[MAX];
int dp[MAX];

/* --------------------------------------------------------------*/



int main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
/* --------------------------------------------------------------*/
cin >>N;
for(int i = 1;i <= N;i++)
{
cin >> a[i];
}
int mi = INF;
for(int k = 1;k <= N;k++)
{
fill(dp,dp+MAX,0);
int ans =0;
dp[0] = a[k];
for(int i = k-1;i >= 1;i--)
{
for(int j = k-1;j >= 1;j--)
{
if(dp[j-1] > a[i])
{
dp[j] = max(a[i],dp[j]);
}
if(dp[j] != 0 && j > ans) ans = j;
}
}
int x = k - 1 - ans;

fill(dp,dp+MAX,0);
dp[0] = a[k];
ans = 0;
for(int i = k+1;i <= N;i++)
{
for(int j = N-k;j >= 1;j--)
{
if(dp[j-1] > a[i])
{
dp[j] = max(a[i],dp[j]);
}
if(dp[j] != 0 && j > ans) ans = j;
}
}
int y = N - k - ans;

if(mi > x + y)
{
mi = x + y;
}
}
cout << mi;
return 0;
}

P1020

状态转移方程和上面一样

dp[i]代表的是截拦i个火箭的时候的最高高度,不能截拦的时候为0

关键语句:

1
2
3
4
if(dp[j-1] >= a[i])
{
dp[j] = max(a[i],dp[j]);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/*-------------------------------------------------------*/

int a[MAX];
int dp[MAX];
vector<int> b;
/* --------------------------------------------------------------*/



int main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);

N= 1;
int x;
int cnt = 0;
while(cin >> x)
{
a[N++] = x;
if(b.size() == 0)
{
b.push_back(x);
cnt++;
}
else
{
int i= 0;
for(i = 0;i < cnt;i++)
{
if(b[i] >= x)
{
b[i] = x;
break;
}
}
if(i == cnt)
{
b.push_back(x);
cnt++;
}
}
sort(b.begin(),b.end());
}
N--;

dp[0] = INF;
for(int i = 1;i <= N;i++)
{
if(dp[i-1] >= a[i])
{
dp[i] = a[i];
}
for(int j = i-1;j >= 1 ;j--)
{
if(dp[j-1] >= a[i])
{
dp[j] = max(a[i],dp[j]);
}
}
}

for(int i = N;i >= 1;i--)
{
if(dp[i] != 0)
{
cout << i <<"\n";
break;
}
}
cout << cnt ;
return 0;
}

二.区间dp

https://www.luogu.org/problemnew/show/P1880

p1880:

首先这个题是环,我们要把环化为链

1
2
3
4
5
for(int i = 1;i <= N;i++)
{
cin >> a[i];
a[i+N] = a[i];
}

还有做一下前缀和的处理,前缀和就是前面的数组元素的和

1
2
3
4
for(int i = 1;i <= 2*N;i++)
{
sum[i] = sum[i-1] + a[i];
}

dp[i][j] 代表的是区间(i,j)的最大和or小

首先我们枚举的是区间的长度,而不是(i,j)

一旦区间长度l确定了,枚举i,j是固定的

然后通过k,把俩堆堆到一起

关键代码:dpa[i][k] + dpa[k+1][j] 注意后面是k+1不是k

1
2
dpa[i][j] = max(dpa[i][j],dpa[i][k] + dpa[k+1][j] + sum[j] - sum[i-1]);
dpi[i][j] = min(dpi[i][j],dpi[i][k] + dpi[k+1][j] + sum[j] - sum[i-1]);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/*-------------------------------------------------------*/

int a[2*MAX];
int dpa[2*MAX][2*MAX];
int dpi[2*MAX][2*MAX];
int sum[2*MAX];

/* --------------------------------------------------------------*/



int main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
/* --------------------------------------------------------------*/
cin >> N;
for(int i = 1;i <= N;i++)
{
cin >> a[i];
a[i+N] = a[i];
}
sum[0] = 0;
for(int i = 0;i <= N;i++)
{
fill(dpa[i],dpa[i]+N+1,0);
fill(dpi[i],dpi[i]+N+1,0);
}
for(int i = 1;i <= 2*N;i++)
{
sum[i] = sum[i-1] + a[i];
}
for(int l = 2;l <= N;l++)
{
for(int i = 1;i+l-1 <= 2*N;i++)
{
int j = i + l - 1;
dpi[i][j] = INF;//why?why?why?
for(int k = i;k < j;k++)
{
dpa[i][j] = max(dpa[i][j],dpa[i][k] + dpa[k+1][j] + sum[j] - sum[i-1]);
dpi[i][j] = min(dpi[i][j],dpi[i][k] + dpi[k+1][j] + sum[j] - sum[i-1]);

//cout << i << " " << j << " " << k <<endl;
//cout <<dpa[i][j] << " " << dpi[i][j] <<endl;
}
}
}
int ma = 0;
int mi = INF;
for(int i = 1;i <= N;i++)
{
ma = max(ma,dpa[i][i+N-1]);
mi = min(mi,dpi[i][i+N-1]);
}
cout << mi << "\n" << ma << "\n";
return 0;
}
相关文章
评论
分享
  • 动态规划背包

    0-1背包 一.01背包划重点:当一件物品只能用一次时,必须要在同一个背包循环中只放一次,所以要容量倒走,根据递推表达式也可以知道 例题1:https://www.luogu.org/problemnew/show/P1060 普通版...

    动态规划背包
  • CF-577-2

    Codeforces Round #577 (Div. 2)A.Important Exam问学生分数总和最大为多少 那么就是每道题选的最多的选项为答案,计算即可 B.Zero Array如果sum是奇数的一定不行 如果是偶数的话就看...

    CF-577-2
  • NC-5

    2019牛客暑期多校训练营(第五场)A.digits 2输出N个N即可 B.generator 1题目思路:平常这个脑子会比比赛时候好用很多 比赛时候看到数据范围也想到了有没有十进制快速幂这种操作,但是没想到怎么实现 牛客这个测评鸡真...

    NC-5
  • ECF-69-2

    Educational Codeforces Round 69 (Rated for Div. 2)A.DIY Wooden Ladder找最长的的俩个,然后看是能放的木板多,还是给的木板多 B.Pillars观察发现这个序列有三种情...

    ECF-69-2
  • NC-4

    2019牛客暑期多校训练营(第四场)A.meeting题目思路:看到就想到之前的换根dp,真的就可以 cfrerooting传送门 我们把他们要去的集合地点作为树根 然后dp[i]表示到达 i 节点需要的最长时间(树深度) 状态转移 ...

    NC-4
  • CF-575-3

    Codeforces Round #575 (Div. 3)A.Three Piles of Candies傻逼题,一人拿一堆,剩下一堆还能随便分,加起来除2 B.Odd Sum Segments一个序列里只有奇数个奇数时和才是奇数 ...

    CF-575-3
  • CF-574-2

    Codeforces Round #574 (Div. 2)A.Drinks Choosing就把可以凑对的凑在一起,不能的俩俩组合 B.Sport Mafia题目思路:算出全放糖果的sum,算出与留下糖果的差cha 可知,每少放一次...

    CF-574-2
  • ECF-67.2

    题目传送门 A:Stickers and Toys三种情况,没有重叠,有重叠,都重叠 B:Letters Shop开个二维数组,记录每一种字母的位置 扫描字符串找到位置最靠后的字母 C:Vasya And Array题解的方法还没搞懂...

    ECF-67.2
  • NC-3

    2019牛客暑期多校训练营(第三场)Crazy Binary String题目思路:定义1为+1,0为-1 扫一遍数组,计算出前缀和,并将每个数字出现的index记录下来 然后逆序往回找,想要区间0和1的个数相等,就要区间和为0 所以...

    NC-3
  • 专题-搜索

    专题-搜索
Please check the parameter of comment in config.yml of hexo-theme-Annie!