题目描述
难度分:1404
输入n(1≤n≤105)和两个长为n的数组b和c(1≤b[i],c[i]≤109)。
构造数组a,满足a[i]都是正整数,且:
- b[i]=max(a[1],a[2],…,a[i]),即数组a的前缀最大值。
- c[i]=max(a[i],a[i+1],…,a[n]),即数组a的后缀最大值。
问:有多少个符合要求的数组a?由于结果可能非常大,需要对结果模109+7。
如果不存在这样的数组a,输出0。
输入样例1
5
1 3 3 3 3
3 3 2 2 2
输出样例1
4
输入样例2
5
1 1 1 2 2
3 2 1 1 1
输出样例2
0
输入样例3
10
1 3776 3776 8848 8848 8848 8848 8848 8848 8848
8848 8848 8848 8848 8848 8848 8848 8848 3776 5
输出样例3
884111967
输入样例4
1
17
17
输出样例4
1
算法
动态规划
这个题看着很像要用DP
解决的类型(计数类问题一般就是用DP
或者组合数学的方法来统计,或者二者都有),结合n≤105的信息,应该是个线性DP
。
状态定义
dp[i]表示的是考虑前i个元素的情况下,能够构造出来的数组数量,因此答案为dp[n]。
状态转移
base case:dp[0]=1,空数组算一种方案。
很显然,b数组是个单调不降的数组,c数组是个单调不增的数组。
- 如果b[i]≠b[i−1],说明b[i]是第一次出现,a[i]必须要是b[i],只有一种方式,但考虑到c[i]的约束,如果b[i]>c[i],就与c[i]=maxnj=ia[j]矛盾了,直接返回0;否则状态转移方程为dp[i]=dp[i−1]。
- 如果b[i]=b[i−1],说明a[i]进入了一个平台,不考虑后缀最大值数组c的话,由于前面已经出现过b[i]这个值,当前位置i可以是[1,b[i]]区间内的任何数。但此时需要考虑c[i]的约束,对称的:c[i]≠c[i+1]时,c[i]是第一次出现,i位置只能是c[i],状态转移方程为dp[i]=dp[i−1]。c[i]=c[i+1]时,c[i]进入了平台,由于后面(i,n]已经出现过c[i]这个值,所以当前位置可以是区间[1,c[i]]内的任何数,综合b[i]的约束,可以取值的区间就是[1,min(b[i],c[i])],状态转移方程为dp[i]=min(b[i],c[i])×dp[i−1]。
复杂度分析
时间复杂度
遍历了遍原数组a进行线性DP
,时间复杂度为O(n)。
空间复杂度
用两个变量last和res滚动,代替了DP
数组,额外空间复杂度为O(1)。
C++ 代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100010, MOD = 1e9 + 7;
int b[N], c[N], dp[N], n;
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &b[i]);
}
for(int i = 1; i <= n; i++) {
scanf("%d", &c[i]);
}
int last = 1, res = 0;
for(int i = 1; i <= n; i++) {
if(b[i] == b[i - 1]) {
if(c[i] == c[i + 1]) {
res = (LL)min(b[i], c[i])*last%MOD;
}else {
res = last;
}
}else {
if(c[i] < b[i]) {
puts("0");
exit(0);
}else {
res = last;
}
}
last = res;
}
printf("%d\n", res);
return 0;
}