2019牛客暑期多校训练营(第一场)

传送门

 

参考资料:

  [1]:官方题解(提取码:t050 )

  [2]:标程(提取码:rvxr )

      [3]:牛客题解汇总

 

 

A.Equivalent Prefixes(单调栈)

•题意

  定义两个数组 u,v ,并且 u,v 都含有 m 个互不相同的元素;

  如果数组 u,v 任意区间的RMQ(区间最小值)对应的下标都相等,则说这两个数组是 "equivalent";

  先给你包含 n 个不同元素的数组 a,b,求使得 a[1,2,...,p] 与 b[1,2,....,p] 为 "equivalen" 的最大的 p;

•题解

  定义数组 L1,L1[ i ]表示在 a 数组中,以 ai 为区间最小值最左可以到达的位置;

  即 RMQ( L1[ i ], i ) = ai

  定义数组 L2,含义与 L1 相同,作用于数组 b;

  对于位置 i ,找到第一个不满足 L1[i] == L2[ i ] 的位置 i,那么,答案就为 i-1;

•Code

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<stack>
 4 using namespace std;
 5 #define ll long long
 6 const int maxn=1e5+50;
 7 
 8 int n;
 9 int a[maxn];
10 int b[maxn];
11 int L1[maxn];
12 int L2[maxn];
13 stack<int >sta;
14 
15 void Work(int *a,int *L)
16 {
17     while(!sta.empty())
18         sta.pop();
19     for(int i=1;i <= n;++i)
20     {
21         while(!sta.empty() && a[sta.top()] >= a[i])
22             sta.pop();
23 
24         L[i]=sta.empty() ? 1:sta.top()+1;
25         sta.push(i);
26     }
27 }
28 int Solve()
29 {
30     Work(a,L1);
31     Work(b,L2);
32 
33     int p=n;
34     for(int i=1;i <= n;++i)
35         if(L1[i] != L2[i])
36         {
37             p=i-1;
38             break;
39         }
40     return p;
41 }
42 int main()
43 {
44     while(~scanf("%d",&n))
45     {
46         for(int i=1;i <= n;++i)
47             scanf("%d",a+i);
48         for(int i=1;i <= n;++i)
49             scanf("%d",b+i);
50 
51         printf("%d\n",Solve());
52     }
53     return 0;
54 }
View Code

 


E.ABBA(DP or 组合数学)

•参考资料

  [1]:唐宋元明清(DP)

  [2]:光芒万丈小太阳(DP)

  [3]:rjmgc丁凯朔(组合数学)(待参考)

•题意

  求包含 n 个 "AB" 和 m 个 "BA" 的总方案数;

题解

  比赛结束当天,查看了参考资料[2]的博文,当时出于似懂非懂的状态;

  今天(2019.7.21)重新看了一下这道题,又看了另一篇博文参考资料[1];

  有种恍然大悟的感觉,但任然欠缺点东西,先记录以下,万一那天顿悟了呢。

  定义 dp[ i ][ j ] 表示当前包含 i 个 'A' 和 j 个 'B' 的合法序列的总方案数;

  如果 i+1 ≤ n+j,转移 : dp[i+1][ j ] += dp[ i ][ j ];

  如果 j+1 ≤ m+i,转移 : dp[ i ][ j+1] += dp[ i ][ j ];

  

  

  这两篇博客对比着理解以下,应该更容易些;(tql)

•Code

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 const int MOD=1e9+7;
 5 const int maxn=4e3+50;
 6 
 7 int n,m;
 8 ll dp[maxn][maxn];
 9 
10 ll Solve()
11 {
12     int s=n+m;
13     for(int i=0;i <= s;++i)
14         for(int j=0;j <= s;++j)
15             dp[i][j]=0;
16     dp[0][0]=1;
17 
18     for(int i=0;i <= s;++i)
19     {
20         for(int j=0;j <= s;++j)
21         {
22             if(i+1 <= n+j)
23                 dp[i+1][j]=(dp[i+1][j]+dp[i][j])%MOD;
24             if(j+1 <= m+i)
25                 dp[i][j+1]=(dp[i][j+1]+dp[i][j])%MOD;
26         }
27     }
28     return dp[s][s];
29 }
30 int main()
31 {
32     while(~scanf("%d%d",&n,&m))
33     {
34         printf("%d\n",Solve());
35     }
36     return 0;
37 }
View Code

 

转载于:https://www.cnblogs.com/violet-acmer/p/11209409.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值