【LeetCode双周赛】第 117 场双周赛

LeetCode第 117 场双周赛

  • 2928. 给小朋友们分糖果 I 简单
  • 2929. 给小朋友们分糖果 II 中等
  • 2930. 重新排列后包含指定子字符串的字符串数目 中等

2928. 给小朋友们分糖果 I 简单

给你两个正整数 n 和 limit 。

请你将 n 颗糖果分给 3 位小朋友,确保没有任何小朋友得到超过 limit 颗糖果,请你返回满足此条件下的 总方案数 。

示例 1:

输入:n = 5, limit = 2
输出:3
解释:总共有 3 种方法分配 5 颗糖果,且每位小朋友的糖果数不超过 2 :(1, 2, 2) ,(2, 1, 2) 和 (2, 2, 1) 。

示例 2:

输入:n = 3, limit = 3
输出:10
解释:总共有 10 种方法分配 3 颗糖果,且每位小朋友的糖果数不超过 3 :(0, 0, 3) ,(0, 1, 2) ,(0, 2, 1) ,(0, 3, 0) ,(1, 0, 2) ,(1, 1, 1) ,(1, 2, 0) ,(2, 0, 1) ,(2, 1, 0) 和 (3, 0, 0) 。

提示:

  • 1 < = n < = 50 1 <= n <= 50 1<=n<=50
  • 1 < = l i m i t < = 50 1 <= limit <= 50 1<=limit<=50

分析:
利用容斥原理,具体分析见第二题

代码:

class Solution {
public:
    int combination(int n, int k){
        if(n<0||k<0||n<k) return 0;
        if(k==0) return 1;
        if(n-k<k) k=n-k;
        int ans=1,tmp=1;
        for(int i=k;i>0;i--,n--){
            ans*=n;
            tmp*=i;
        }
        return ans/tmp;
    }

    int distributeCandies(int n, int limit) {
        return combination(n+3-1, n) - 3 * combination(n-(limit+1)+3-1, n-(limit+1)) + 3 * combination(n-2*(limit+1)+3-1, n-2*(limit+1)) - combination(n-3*(limit+1)+3-1, n-3*(limit+1));
    }
};


2929. 给小朋友们分糖果 II 中等

给你两个正整数 n 和 limit 。

请你将 n 颗糖果分给 3 位小朋友,确保没有任何小朋友得到超过 limit 颗糖果,请你返回满足此条件下的 总方案数 。

示例 1:

输入:n = 5, limit = 2
输出:3
解释:总共有 3 种方法分配 5 颗糖果,且每位小朋友的糖果数不超过 2 :(1, 2, 2) ,(2, 1, 2) 和 (2, 2, 1) 。

示例 2:

输入:n = 3, limit = 3
输出:10
解释:总共有 10 种方法分配 3 颗糖果,且每位小朋友的糖果数不超过 3 :(0, 0, 3) ,(0, 1, 2) ,(0, 2, 1) ,(0, 3, 0) ,(1, 0, 2) ,(1, 1, 1) ,(1, 2, 0) ,(2, 0, 1) ,(2, 1, 0) 和 (3, 0, 0) 。

提示:

  • 1 < = n < = 1 0 6 1 <= n <= 10^6 1<=n<=106
  • 1 < = l i m i t < = 1 0 6 1 <= limit <= 10^6 1<=limit<=106

分析:
将 n 颗糖果,分给3个小朋友,每个小朋友的糖果不可以超过limit。如果直接进行方案的枚举,如果数据较大的话,很容易超时。同时枚举时可能会遇到方案十分复杂的情况。
此时我们换一个思路,列举出分糖果的所有情况,再计算出不符合要求的情况,二者相减即可得到最终结果。

分糖果的所有情况: 将n颗糖果分给3个小朋友,我们可以将n颗糖果按顺序排列,使用两块隔板将其分成三份(允许某些小朋友分到的糖果为0)。
将糖果看做是1,隔板看做是0,则分糖果的所有情况数即为:{n个1, (3-1)个0} 这一多重集合的全排列数,因此结果为:
( n + 3 − 1 ) ! / n ! ( n + 3 − 1 ) ! / n ! ( n + 3 − 1 ) ! / n ! (n+3−1)!/n!(n + 3 -1)! / n!(n+3−1)!/n! (n+31)!/n!(n+31)!/n!(n+31)!/n!

不符合要求的情况: 假设三个小朋友分别是a、b、c,对应的不符合题意的情况为A、B、C,则情况如下:

  • A:a分得的糖果>=limit+1
  • B:b分得的糖果>=limit+1
  • C:c分得的糖果>=limit+1

同时还有A∩B、A∩C、B∩C、A∩B∩C。A和B中均包含了A∩B,依次类推。 最终得到的不符合要求的总方式数为:A + B + C - A∩B - A∩C - B∩C + A∩B∩C
A的计算方法也是类似于总情况的计算方法,不过为保证a分得的糖果一定不满足情况,因此要在总数上减去limit+1,计算公式如下:
C ( n − ( l i m i t + 1 ) + 3 − 1 , n − ( l i m i t + 1 ) ) C(n−(limit+1)+3−1, n−(limit+1)) C(n(limit+1)+31,n(limit+1))

其他情况类似,最终情况见代码!

代码:


class Solution {
public:
    long long combination(int n, int k){
        if(n<0||k<0||n<k) return 0;
        if(k==0) return 1;
        if(n-k<k) k=n-k;
        long long ans=1;
        for(int i=1;i<=k;i++,n--){
            ans*=n;
            ans/=i;// 连续的i个数,一定有i的倍数,因此可以直接除
        }
        return ans;
    }

    long long distributeCandies(int n, int limit) {
        return combination(n+3-1, n) - 3 * combination(n-(limit+1)+3-1, n-(limit+1)) + 3 * combination(n-2*(limit+1)+3-1, n-2*(limit+1)) - combination(n-3*(limit+1)+3-1, n-3*(limit+1));
    }
};


2930. 重新排列后包含指定子字符串的字符串数目 中等

给你一个整数 n 。

如果一个字符串 s 只包含小写英文字母,且 将 s 的字符重新排列后,新字符串包含 子字符串 “leet” ,那么我们称字符串 s 是一个 好 字符串。

比方说:

字符串 “lteer” 是好字符串,因为重新排列后可以得到 “leetr” 。
“letl” 不是好字符串,因为无法重新排列并得到子字符串 “leet” 。
请你返回长度为 n 的好字符串 总 数目。

由于答案可能很大,将答案对 1 0 9 + 7 10^9 + 7 109+7 取余 后返回。

子字符串 是一个字符串中一段连续的字符序列。

示例 1:

输入:n = 4
输出:12
解释:总共有 12 个字符串重新排列后包含子字符串 “leet” :“eelt” ,“eetl” ,“elet” ,“elte” ,“etel” ,“etle” ,“leet” ,“lete” ,“ltee” ,“teel” ,“tele” 和 “tlee” 。

示例 2:

输入:n = 10
输出:83943898
解释:长度为 10 的字符串重新排列后包含子字符串 “leet” 的方案数为 526083947580 。所以答案为 526083947580 % (109 + 7) = 83943898 。

提示:

  • 1 < = n < = 1 0 5 1 <= n <= 10^5 1<=n<=105

分析:
只需要包含 leet 这四个字母的字符串就一定满足情况,但这样很难计算。利用容斥原理,计算所有的情况,减去不满足的情况,最终得到结果。不满足的情况分以下几种:

  • L:不包含 l 的字符串
  • T:不包含 t 的字符串
  • E:不包含 e 或者只包含一个e的字符串

同时这三种情况中满足两个或者全都满足也不符合情况,计算对应的数量。
需要注意取模的处理,我是按照题解的处理方式进行的处理。在分开计算的时候,是会出现溢出的情况。

代码:

class Solution {
public:
    const long long Mod = 1e9+7;

    long long  pow(int k,int n){
        long long ans=1, cnt = k;
        while(n){
            if(n&1){
                ans=((ans%Mod)*(cnt%Mod))%Mod;
            }
            cnt=(cnt%Mod)*(cnt%Mod);
            n>>=1;
        }
        return ans%Mod;
    }

    int stringCount(int n) {
        if(n<4) return 0;
        long long ans = ((pow(26, n)%Mod - (75+n)%Mod * pow(25, n-1)%Mod + (72+2*n)%Mod*pow(24, n-1)%Mod - (n+23)%Mod*pow(23,n-1)%Mod)%Mod+Mod)%Mod;
        return ans;
    }
};


你可能感兴趣的:(LeetCode,leetcode,算法,c++)