2022-04-03每日刷题打卡

2022-04-03每日刷题打卡

01序列2 - 题目 - Daimayuan Online Judge

又是大家最喜欢的01序列问题了呢

这次的问题非常的简单,c觉得一个01序列中两个1之间至少要有k个0,现在他要构造出一个长度为n的01序列,请问他有多少种不同的构造方法

这个数字可能会非常大,请你对10^9+7取模

输入格式

一行,给出两个整数n,k

输出格式

一个整数,代表不同的构造方法数

数据范围

1≤n≤10^6

0≤k<n

样例输入
4 2
样例输出
6

首先题目说了,每两个1直接要有k个0,按照样例来说,n=4,k=2的情况有0000,1000,0100,0010,0001和1001。

发现没有,一直在变的其实是1的位置,0的位置不重要,我们只要保证两个1之间有k个0就行,剩下的位置可以随便排列。那我们就从0枚举1的数量i,然后剩下的位置全塞0就行,但0的数量最少要有(i-1)*k。为了方便其实我们可以忽略掉0,即把1都挨着,只要我们默认两个1之间有k个0就行,这样剩下01串的长度就是n-(i-1) *k,我们只要算在这个长度下,1能有多少种不同的排序即可。这就是高中知识了:C(i)(n-(i-1) *k)。至于C用代码怎么算这里便不多做展开了,感兴趣的可以自行百度学习。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n';
typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 1000050, MOD = 1e9 + 7;

ll fact[N], infact[N];

ll qmi(int a, int b)
{
    ll res = 1;
    while (b)
    {
        if (b & 1) res = res * a % MOD;
        a = a * (ll)a % MOD;
        b >>= 1;
    }
    return res;
}

void init()
{
    fact[0] = infact[0] = 1;
    for (int i = 1; i < N; i++)
        fact[i] = fact[i - 1] * i % MOD;

    infact[N - 1] = qmi(fact[N - 1], MOD - 2);
    for (int i = N - 2; i; i--)
        infact[i] = infact[i + 1] * (i + 1) % MOD;
}

int C(int a, int b)
{
    return (fact[a] * infact[b] % MOD * infact[a - b] % MOD) % MOD;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n, k;
    init();
    cin >> n >> k;
    int i = 1;
    ll res = 1;
    while (i <= n - (i - 1) * k)
    {
        res = (res + C(n - (i - 1) * k, i) % MOD) % MOD;
        i++;
    }
    cout << res << endl;
    return 0;
}

力扣

239. 滑动窗口最大值

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回 滑动窗口中的最大值 。

示例 1:

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值


[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104
  • 1 <= k <= nums.length

求区间最大值的线段树。和正常的线段树没什么区别,就是每个父节点的值不再是两个子节点之和,而是两个子节点中的最大值。建完树后,从下标为0开始每次求长度为k的区间最大值。

class Solution {
public:
    int a[100050], f[500050], n, m;   
    void buildtree(int k, int l, int r)
    {
        if (l == r)
        {
            f[k] = a[l];
            return ;
        }
        int m = (l + r) / 2;
        buildtree(k + k, l, m);
        buildtree(k + k + 1, m + 1, r);
        f[k] = max(f[k + k], f[k + k + 1]);
    }

    int quiry(int k, int l, int r, int x, int y)
    {
        if (l == x && r == y)return f[k];
        int m = (l + r) / 2;
        if (y <= m)
            return quiry(k + k, l, m, x, y);
        else
            if (x > m)return quiry(k + k + 1, m + 1, r, x, y);
            else
                return max(quiry(k + k, l, m, x, m), quiry(k + k + 1, m + 1, r, m + 1, y));
    }
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        n=nums.size();
        vector<int>v;
        for(int i=1;i<=n;i++)a[i]=nums[i-1];
        buildtree(1,1,n);
        for(int i=1;i+k-1<=n;i++)
        {
            v.push_back(quiry(1,1,n,i,i+k-1));
        }
        return v;
    }
};
5219. 每个小孩最多能分到多少糖果

给你一个 下标从 0 开始 的整数数组 candies 。数组中的每个元素表示大小为 candies[i] 的一堆糖果。你可以将每堆糖果分成任意数量的 子堆 ,但 无法 再将两堆合并到一起。

另给你一个整数 k 。你需要将这些糖果分配给 k 个小孩,使每个小孩分到 相同 数量的糖果。每个小孩可以拿走 至多一堆 糖果,有些糖果可能会不被分配。

返回每个小孩可以拿走的 最大糖果数目 。

示例 1:

输入:candies = [5,8,6], k = 3
输出:5
解释:可以将 candies[1] 分成大小分别为 5 和 3 的两堆,然后把 candies[2] 分成大小分别为 5 和 1 的两堆。现在就有五堆大小分别为 5、5、3、5 和 1 的糖果。可以把 3 堆大小为 5 的糖果分给 3 个小孩。可以证明无法让每个小孩得到超过 5 颗糖果。

二分答案,我们先算一下糖果的总和,看是否小于孩子数量,如果小于说明糖果不够孩子们分的直接返回0,同时求一下这些糖果堆的最大数是多少。如果总和大于孩子数量,我们就二分答案来找最值。下界就是1(每个孩子最少也能得到一个糖),上界就是我们求得的最大值,然后每次取中间值m,判断糖果堆能否分成k个m的糖果堆,如果可以,说明孩子们能得到的糖果还能多,我们去右边继续找。如果分不了,说明这个糖果数量有点多了,我们去左边找。最后找到的就是孩子们能得到的最大糖果数。

class Solution {
public:
    bool check(int x,vector<int>v,long long k)
    {
        int n=v.size();
        for(int i=0;i<n;i++)
        {
            while(v[i]>=x)
            {
                k-=v[i]/x;
                v[i]%=x;
            }
            if(k<=0)return true;
        }
        return false;
    }
    int maximumCandies(vector<int>& candies, long long k) {
        long long sum=0;
        int mx=-1e9;
        for(auto i:candies)
        {
            sum+=i;
            mx=max(mx,i);
        }
        if(sum<k)return 0;
        else if(sum==k)return 1;
        int res=0;
        int l=1,r=mx;
        while(l<r)
        {
            int m = (l + r + 1) / 2;
            if (check(m, candies, k))l = m;
            else r = m - 1;
        }
        return l;
    }
};
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值