【动态规划】【组合数学】1866. 恰有 K 根木棍可以看到的排列数目

2024-02-19 21:12

本文主要是介绍【动态规划】【组合数学】1866. 恰有 K 根木棍可以看到的排列数目,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

作者推荐

【深度优先搜索】【树】【有向图】【推荐】685. 冗余连接 II

本文涉及知识点

动态规划汇总

LeetCode1866. 恰有 K 根木棍可以看到的排列数目

有 n 根长度互不相同的木棍,长度为从 1 到 n 的整数。请你将这些木棍排成一排,并满足从左侧 可以看到 恰好 k 根木棍。从左侧 可以看到 木棍的前提是这个木棍的 左侧 不存在比它 更长的 木棍。
例如,如果木棍排列为 [1,3,2,5,4] ,那么从左侧可以看到的就是长度分别为 1、3 、5 的木棍。
给你 n 和 k ,返回符合题目要求的排列 数目 。由于答案可能很大,请返回对 109 + 7 取余 的结果。
示例 1:
输入:n = 3, k = 2
输出:3
解释:[1,3,2], [2,3,1] 和 [2,1,3] 是仅有的能满足恰好 2 根木棍可以看到的排列。
可以看到的木棍已经用粗体+斜体标识。
示例 2:
输入:n = 5, k = 5
输出:1
解释:[1,2,3,4,5] 是唯一一种能满足全部 5 根木棍可以看到的排列。
可以看到的木棍已经用粗体+斜体标识。
示例 3:
输入:n = 20, k = 11
输出:647427950
解释:总共有 647427950 (mod 109 + 7) 种能满足恰好有 11 根木棍可以看到的排列。
提示:
1 <= n <= 1000
1 <= k <= n

动态规划

原理

n根木棍,枚举最后一个木棍:
{ 相比 n − 1 根木框,多看到一根木框 最后一根木棍是 n 相比 n − 1 根木框,看到相同的木框 最后一根木棍不是 n \begin{cases} 相比n-1根木框,多看到一根木框 & 最后一根木棍是n \\ 相比n-1根木框,看到相同的木框& 最后一根木棍不是n \\ \end{cases} {相比n1根木框,多看到一根木框相比n1根木框,看到相同的木框最后一根木棍是n最后一根木棍不是n
假定最后一个木框是j ,由于它在木棍n之后,所以必定看不到。删除j,不影响结果。删除后,将大于等于j的木棍减少1,就是1到n-1的一个排列。

动态规划的状态表示

pre[j] 表示i-1根木框,能看到j根木棍的可能数。
dp[j] 表示i+1根木框,能看到j根木棍的可能数。

动态规划的转移方程

处理最后一个木棍为n:
dp={0} dp += pre;
处理最后一根木棍不是n:
dp[j] += pre[j]*(i-1)
除了初始状态,其它状态pre[0]都为0。

初始状态

pre = {1}

动态规划的填表顺序

i从0到大。

动态规划的返回值

pre[k]

代码

核心代码

template<int MOD = 1000000007>
class C1097Int
{
public:C1097Int(long long llData = 0) :m_iData(llData% MOD){}C1097Int  operator+(const C1097Int& o)const{return C1097Int(((long long)m_iData + o.m_iData) % MOD);}C1097Int& operator+=(const C1097Int& o){m_iData = ((long long)m_iData + o.m_iData) % MOD;return *this;}C1097Int& operator-=(const C1097Int& o){m_iData = (m_iData + MOD - o.m_iData) % MOD;return *this;}C1097Int  operator-(const C1097Int& o){return C1097Int((m_iData + MOD - o.m_iData) % MOD);}C1097Int  operator*(const C1097Int& o)const{return((long long)m_iData * o.m_iData) % MOD;}C1097Int& operator*=(const C1097Int& o){m_iData = ((long long)m_iData * o.m_iData) % MOD;return *this;}bool operator<(const C1097Int& o)const{return m_iData < o.m_iData;}C1097Int pow(long long n)const{C1097Int iRet = 1, iCur = *this;while (n){if (n & 1){iRet *= iCur;}iCur *= iCur;n >>= 1;}return iRet;}C1097Int PowNegative1()const{return pow(MOD - 2);}int ToInt()const{return m_iData;}
private:int m_iData = 0;;
};class Solution {
public:int rearrangeSticks(int n, int k) {vector<C1097Int<> > pre = { 1 };for (int i = 1; i <= n; i++){vector<C1097Int<>> dp = { 0 };dp.insert(dp.end(), pre.begin(), pre.end());//最后一根木棍是 ifor (int j = 1; j < pre.size(); j++){//最后一根木棍是[1,i)dp[j] += pre[j] * (i - 1);}pre.swap(dp);}return pre[k].ToInt();}
};

测试用例


template<class T>
void Assert(const T& t1, const T& t2)
{assert(t1 == t2);
}template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{if (v1.size() != v2.size()){assert(false);return;}for (int i = 0; i < v1.size(); i++){Assert(v1[i], v2[i]);}}int main()
{	int n, k;{Solution sln;n =3 ,k=2 ;auto res = sln.rearrangeSticks(n, k);Assert(res, 3);}{Solution sln;n = 5, k = 5;auto res = sln.rearrangeSticks(n, k);Assert(res, 1);}{Solution sln;n = 20, k = 11;auto res = sln.rearrangeSticks(n, k);Assert(res, 647427950);}
}

2023年2月

class C1097Int
{
public:
C1097Int(int iData = 0) :m_iData(iData)
{

 }C1097Int  operator+(const C1097Int& o)const{return C1097Int(((long long)m_iData + o.m_iData) % s_iMod);}C1097Int&  operator+=(const C1097Int& o){m_iData = ((long long)m_iData + o.m_iData) % s_iMod;return *this;}C1097Int  operator*(const C1097Int& o)const{return((long long)m_iData *o.m_iData) % s_iMod;}C1097Int&  operator*=(const C1097Int& o){m_iData =((long long)m_iData *o.m_iData) % s_iMod;return *this;}int ToInt()const{return m_iData;}

private:
int m_iData = 0;;
static const int s_iMod = 1000000007;
};

int operator+(int iData, const C1097Int& int1097)
{
int iRet = int1097.operator+(C1097Int(iData)).ToInt();
return iRet;
}

int& operator+=(int& iData, const C1097Int& int1097)
{
iData = int1097.operator+(C1097Int(iData)).ToInt();
return iData;
}

int operator*(int iData, const C1097Int& int1097)
{
int iRet = int1097.operator*(C1097Int(iData)).ToInt();
return iRet;
}

int& operator*=(int& iData, const C1097Int& int1097)
{
iData = int1097.operator*(C1097Int(iData)).ToInt();
return iData;
}

template
void MinSelf(T* seft, const T& other)
{
*seft = min(*seft, other);
}

template
void MaxSelf(T* seft, const T& other)
{
*seft = max(*seft, other);
}

int GetNotRepeateNum(int len, int iHasSel)
{
if (0 == len)
{
return 1;
}
if ((0 == iHasSel) && (1 == len))
{
return 10;
}
int iRet = 1;
if (iHasSel > 0)
{
for (int tmp = 10 - iHasSel; (tmp >= 2)&& len ; tmp–,len–)
{
iRet *= tmp;
}
}
else
{
iRet *= 9;
len–;
for (int tmp=9; (tmp>=2)&&len; len–,tmp–)
{
iRet *= tmp;
}
}
return iRet;
}

int GCD(int n1, int n2)
{
int t1 = min(n1, n2);
int t2 = max(n1, n2);
if (0 == t1)
{
return t2;
}
return GCD(t2%t1, t1);
}

void CreateMaskVector(vector& v,const int* const p,int n )
{
const int iMaxMaskNum = 1 << n;
v.resize(iMaxMaskNum);
for (int i = 0; i < n; i++)
{
v[1 << i] = p[i];
}
for (int mask = 1; mask < iMaxMaskNum ; mask++)
{
const int iSubMask = mask&(-mask);
v[mask] = v[iSubMask] + v[mask-iSubMask];
}
}

class Solution {
public:
int rearrangeSticks(int n, int k) {
vector pre(k + 1);
pre[0] = 1;
for (int iN = 1; iN <= n; iN++)
{
vector dp(k + 1);
for (int j = 1; j <= k; j++)
{
dp[j] = pre[j - 1] + pre[j] * (iN - 1);
}
pre.swap(dp);
}
return pre[k].ToInt();
}
};

2023年9月

class Solution {
public:
int rearrangeSticks(int n, int k) {
vector<C1097Int<>> pre = { 1 };
for (int i = 1; i <= n; i++)
{
vector<C1097Int<>> dp(i + 1);
for (int j = 0; j < pre.size(); j++)
{
dp[j + 1] += pre[j];
dp[j] += pre[j] * (i - 1);
}
pre.swap(dp);
}
return pre[k].ToInt();
}
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关

下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

这篇关于【动态规划】【组合数学】1866. 恰有 K 根木棍可以看到的排列数目的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/725992

相关文章

hdu1496(用hash思想统计数目)

作为一个刚学hash的孩子,感觉这道题目很不错,灵活的运用的数组的下标。 解题步骤:如果用常规方法解,那么时间复杂度为O(n^4),肯定会超时,然后参考了网上的解题方法,将等式分成两个部分,a*x1^2+b*x2^2和c*x3^2+d*x4^2, 各自作为数组的下标,如果两部分相加为0,则满足等式; 代码如下: #include<iostream>#include<algorithm

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

hdu4869(逆元+求组合数)

//输入n,m,n表示翻牌的次数,m表示牌的数目,求经过n次操作后共有几种状态#include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>#include<map>#include<stdio.h>#include<stdlib.h>#includ

动态规划---打家劫舍

题目: 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。 思路: 动态规划五部曲: 1.确定dp数组及含义 dp数组是一维数组,dp[i]代表

uva 10014 Simple calculations(数学推导)

直接按照题意来推导最后的结果就行了。 开始的时候只做到了第一个推导,第二次没有继续下去。 代码: #include<stdio.h>int main(){int T, n, i;double a, aa, sum, temp, ans;scanf("%d", &T);while(T--){scanf("%d", &n);scanf("%lf", &first);scanf

uva 10025 The ? 1 ? 2 ? ... ? n = k problem(数学)

题意是    ?  1  ?  2  ?  ...  ?  n = k 式子中给k,? 处可以填 + 也可以填 - ,问最小满足条件的n。 e.g k = 12  - 1 + 2 + 3 + 4 + 5 + 6 - 7 = 12 with n = 7。 先给证明,令 S(n) = 1 + 2 + 3 + 4 + 5 + .... + n 暴搜n,搜出当 S(n) >=

uva 11044 Searching for Nessy(小学数学)

题意是给出一个n*m的格子,求出里面有多少个不重合的九宫格。 (rows / 3) * (columns / 3) K.o 代码: #include <stdio.h>int main(){int ncase;scanf("%d", &ncase);while (ncase--){int rows, columns;scanf("%d%d", &rows, &col

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

软考系统规划与管理师考试证书含金量高吗?

2024年软考系统规划与管理师考试报名时间节点: 报名时间:2024年上半年软考将于3月中旬陆续开始报名 考试时间:上半年5月25日到28日,下半年11月9日到12日 分数线:所有科目成绩均须达到45分以上(包括45分)方可通过考试 成绩查询:可在“中国计算机技术职业资格网”上查询软考成绩 出成绩时间:预计在11月左右 证书领取时间:一般在考试成绩公布后3~4个月,各地领取时间有所不同

poj 2976 分数规划二分贪心(部分对总体的贡献度) poj 3111

poj 2976: 题意: 在n场考试中,每场考试共有b题,答对的题目有a题。 允许去掉k场考试,求能达到的最高正确率是多少。 解析: 假设已知准确率为x,则每场考试对于准确率的贡献值为: a - b * x,将贡献值大的排序排在前面舍弃掉后k个。 然后二分x就行了。 代码: #include <iostream>#include <cstdio>#incl