问题描述
小M拥有一个长度为n的数组 a,由于他非常喜欢数字 w,他希望将所有数组中的数都变为 w。
小M每次操作可以选择一个区间 [l, r],并将该区间内的所有数字都加 1(包括左右边界 l 和 r)。但为了让挑战更具趣味性,小M要求每次操作的l均不相同,r也均不相同。
小M现在想知道,有多少种不同的操作方案可以让数组中的所有数都变为 w。注意,如果所有操作的区间相同,则视为同一种操作方式,操作顺序不同并不会形成新的方案。
解题思路
先计算每个数需要增加的大小;
定义新数组diff[],diff[i]=w-a[i],
diff[i]即a[i]需要增加大小;
因为每个操作区间可使a[i]增加1,所以diff[i]即为包含a[i]的区间数量;
例子
_1_2_3_4_5_
问题可转化为在_中填入[ 、] 且两者数量相同;
因为每个[l,r]的l不相同,r也不相同,所以对于每个_有三种填入方式[、]、][;
对于数字x确保其左边有x个[;
可通过动态规划求解:
定义l记录[的数量,l即为包含当前数字的区间数量,定义ans记录方案数;
遍历数组
若l==diff[i]+1则在i前填入],]可匹配此前的任何一个[,有l种匹配方法,所以方案数ans=ans*l,l=l-1;
若l==diff[i]-1则在i前填入[,l++;
若l==diff[i]&&l!=0则在i前填入][或不填,相当于将两个相邻且相等的数一起加或分开加,此时有两种情况ans=ans*2,l不变;
其他情况或遍历至最后l!=0则无可行方案;
代码样例
#include <iostream>
#include <vector>
using namespace std;
// Edit your code here
int solution(int n, int w, const std::vector<int>& array) {
int mod=1e9+7; // 定义一个模数,用于防止结果过大
int l=0,ans=1;
vector<int>diff(n+2); //n个数有n+1个空
for(int i=0;i<n;i++){
diff[i+1]=w-array[i]; // 计算每个位置需要增加的次数
if(diff[i+1]<0)return 0; //array[i]<w 直接返回0
}
for(int i=1;i<=n+1;i++){
if(diff[i]==0){ // 当前位置不需要增加
if(l>1)return 0;
if(l==0)continue;
}
if(diff[i]==diff[i-1]+1){ // 当前位置需要增加的次数比前一个位置多 1
l++;
}
else if(diff[i]==diff[i-1]-1){ // 当前位置需要增加的次数比前一个位置少 1
ans=(ans*l)%mod;
l--;
}
else if(diff[i]==diff[i-1]){ // 当前位置需要增加的次数与前一个位置相同
ans=(ans*2)%mod;
}
else return 0; //其他情况均不可行
}
if(l!=0)return 0; //`]`所需位置不足
else return ans;
}
int main() {
// Add your test cases here
std::cout << (solution(2, 2, std::vector<int>{1, 1}) == 2) << std::endl;
std::cout << (solution(3, 3, std::vector<int>{1, 2, 3}) == 0) << std::endl;
std::cout << (solution(4, 2, std::vector<int>{1, 1,1,1}) == 8) << std::endl;
return 0;
}