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