T3. 挑剔的美食家
作为一名挑剔的美食家,小猴对食物是很讲究的,哪怕摆在面前的只有若干香蕉和苹果,小猴依然有他的讲究。
已知目前已有 根香蕉和 个苹果,小猴制定了以下规则来决定自己的食用顺序:
- 每个香蕉都被认为是独特的个体,可以理解为编号为 的香蕉各不同
- 每个苹果之间没有区别
- 每个时刻小猴只食用一个水果
由于小猴更喜欢香蕉,因此要求在吃第 个苹果之前必须已经至少吃了 个香蕉。( 可能是负数)并对结果模 。
小猴现在希望知道,满足条件的前提下,有多少种不同的食用顺序方案。
(注:两个方案是不同的,当且仅当有至少一个时刻食用了不同的水果或者不同编号的香蕉)
限制:
- 对于 的数据:
- 对于 的数据:
算法分析
部分分1:暴搜,用回溯法得到每个香蕉的排列
代码实现
#include <bits/stdc++.h> using namespace std; int n, m, k, ans; bool vis[15]; void dfs(int a, int b) { if (a > n or b > m) return; if (a == n and b == m) { ans++; return; } for (int i = 1; i <= n; ++i) { if (vis[i]) continue; vis[i] = 1; dfs(a+1, b); vis[i] = 0; } if (a > b+k) dfs(a, b+1); } int main() { cin >> n >> m >> k; dfs(0, 0); cout << ans << '\n'; return 0; }
部分分2:计数原理
香蕉排列顺序:1. 无序版方案 2. 内部排列:分步计数,乘法原理
那么答案就是无序列版方案的
代码实现
#include <bits/stdc++.h> using namespace std; using ll = long long; //const int mod = 998244353; const int mod = 1000000007; struct mint { ll x; mint(ll x=0):x((x%mod+mod)%mod) {} mint operator-() const { return mint(-x); } mint& operator+=(const mint a) { if ((x += a.x) >= mod) x -= mod; return *this; } mint& operator-=(const mint a) { if ((x += mod-a.x) >= mod) x -= mod; return *this; } mint& operator*=(const mint a) { (x *= a.x) %= mod; return *this; } mint operator+(const mint a) const { return mint(*this) += a; } mint operator-(const mint a) const { return mint(*this) -= a; } mint operator*(const mint a) const { return mint(*this) *= a; } mint pow(ll t) const { if (!t) return 1; mint a = pow(t>>1); a *= a; if (t&1) a *= *this; return a; } // for prime mod mint inv() const { return pow(mod-2); } mint& operator/=(const mint a) { return *this *= a.inv(); } mint operator/(const mint a) const { return mint(*this) /= a; } }; istream& operator>>(istream& is, mint& a) { return is >> a.x; } ostream& operator<<(ostream& os, const mint& a) { return os << a.x; } int n, m, k; mint ans; bool vis[15]; void dfs(int a, int b) { if (a > n or b > m) return; if (a == n and b == m) { ans += 1; return; } dfs(a+1, b); if (a > b+k) dfs(a, b+1); } int main() { cin >> n >> m >> k; dfs(0, 0); for (int i = 1; i <= n; ++i) { ans *= i; } cout << ans << '\n'; return 0; }
满分做法:
记 dp[i][j]
表示吃了 个香蕉, 个苹果的方案数(无序)
转移方程:
初值:
- , 当
最后的答案为
代码实现
#include <bits/stdc++.h> using namespace std; using ll = long long; //const int mod = 998244353; const int mod = 1000000007; struct mint { ll x; mint(ll x=0):x((x%mod+mod)%mod) {} mint operator-() const { return mint(-x); } mint& operator+=(const mint a) { if ((x += a.x) >= mod) x -= mod; return *this; } mint& operator-=(const mint a) { if ((x += mod-a.x) >= mod) x -= mod; return *this; } mint& operator*=(const mint a) { (x *= a.x) %= mod; return *this; } mint operator+(const mint a) const { return mint(*this) += a; } mint operator-(const mint a) const { return mint(*this) -= a; } mint operator*(const mint a) const { return mint(*this) *= a; } mint pow(ll t) const { if (!t) return 1; mint a = pow(t>>1); a *= a; if (t&1) a *= *this; return a; } // for prime mod mint inv() const { return pow(mod-2); } mint& operator/=(const mint a) { return *this *= a.inv(); } mint operator/(const mint a) const { return mint(*this) /= a; } }; istream& operator>>(istream& is, mint& a) { return is >> a.x; } ostream& operator<<(ostream& os, const mint& a) { return os << a.x; } int n, m, k; mint dp[1005][1005]; mint ans; int main() { cin >> n >> m >> k; for (int i = 0; i <= n; ++i) dp[i][0] = 1; for (int j = 0; j <= m and 0-j >= k; ++j) dp[0][j] = 1; for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m and i-j >= k; ++j) { dp[i][j] = dp[i-1][j] + dp[i][j-1]; } } ans = dp[n][m]; for (int i = 1; i <= n; ++i) { ans *= i; } cout << ans << '\n'; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现