111.小M的幸运数列变换 题解| 豆包MarsCode AI刷题

66 阅读3分钟

问题描述

小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;
}