题单 · 习题解析

洛谷 P1313 [NOIP 2011 提高组] 计算系数

★★★ 这道题最值钱的一件事**不在算法上**(算法只有一行二项式定理:系数 = C(k,n)·aⁿ·bᵐ),在**数据范围那三行**:30% 档 `k ≤ 10` 正好罩住「long long 阶乘直接算」(它的线精确在 **k = 21**,因为 21! 是第一个装不下的)⇒ **第 ① 版稳拿 30 分**;★★★ 而 50% 档写着 **a = 1、b = 1** —— 题面把多项式故意写成 **(by+ax)ᵏ**(b 在前),顺手就会把系数写成 aᵐ·bⁿ,而 **a = b 时两者恒等** ⇒ **「a、b 弄反」这个错法稳拿 50 分**,那一档是它**能证的精确的 0**(照题面随机是 299/300);★★ **第 ③ 版(杨辉三角)就已经 AC** —— 500 500 次加法、0.47 ms、余量 2143 倍,而阶乘+逆元那套模板快 76 倍却**一分钱用不上**(这道题只问一次)⇒ [「技巧成立」和「该用它」是两句话](/sol/p1776/);★★ 一个「看着像下标写反、其实恒等」的版本:C(k,m) ≡ C(k,n)(题面保证 n+m=k),三个档全是 0,**自检就是放开那句约束** ⇒ 当场 296/300;★ 而「int + 忘了 a %= p」的线精确在 **a ≥ 46341**(两件各自无害的事凑在一起才炸);⚠⚠ **官方样例 `1 1 3 1 2` 对五个待测版本全部没有区分度**(五个全放过),而五个原因都指向样例里那两个 1

原题:洛谷 P1313出自 第 43 章 组合数与递推 的题单题面本地存档:2026-09-03
⚠ 先自己写一遍,再往下看

这一页不是标准答案,是一条阶梯:把大多数人真实会写出的第一版摆出来, 看它错在哪、慢在哪,再一步一步改。所以它对「已经自己动手撞过一次墙」的人最有用。
还没写过的话,先去写 —— 写出来的哪怕是错的,也比直接看这一页收获大。

0题目原文(本地存了一份)

为什么要在这儿抄一份题面

原题在洛谷上(页头有链接)。别人的网站不归我们管,打不开、改版、题号调整都可能发生。 所以每个解析页都把题面转录一份存在本地,跟着仓库一起进版本库。

转录自洛谷 P1313,日期见页头。两边不一致时信原站。

题目描述

给定一个多项式 (by + ax)ᵏ,请求出多项式展开后 xⁿ × yᵐ 项的系数。

输入格式

输入共一行,包含 5 个整数,分别为 a, b, k, n, m,每两个整数之间用一个空格隔开。

输出格式

输出共一行,包含一个整数,表示所求的系数。

这个系数可能很大,输出对 10007 取模后的结果。

数据范围

  • 对于 30% 的数据,有 0 ≤ k ≤ 10
  • 对于 50% 的数据,有 a = 1b = 1
  • 对于 100% 的数据,有 0 ≤ k ≤ 10000 ≤ n, m ≤ kn + m = k0 ≤ a, b ≤ 10⁶

noip2011 提高组 day2 第 1 题。时限 1 秒,内存 125 MB(128000 KB)。

输入输出样例

输入

1 1 3 1 2

输出

3

a = 1b = 1k = 3n = 1m = 2(y + x)³x¹y² 的系数是 C(3,1) = 3

1一行纸上推导:二项式定理

★ 这道题的算法部分只有一行

(by + ax)ᵏ 展开,每一项是「从 k 个括号里挑 n 个出 ax、剩下 m 个出 by」:

(by + ax)ᵏ = Σᵢ₌₀..ₖ C(k, i) · (ax)ⁱ · (by)ᵏ⁻ⁱ

xⁿyᵐ 那一项的系数 = C(k, n) · aⁿ · bᵐ

剩下的全是这一章的活:C(k, n) mod 10007 怎么算、aⁿ mod 10007 怎么算 (后者就是第 42 章那五行)。

★ 两件白送的好事都写在题面里10007质数,而 k ≤ 1000 < 10007本章第 6 步 那个「p > n」的前提在这里是满足的,逆元那一套可以放心用。 (⚠ 下一道题 P3807 就不满足了 —— 那才是它失效的场。)

2第 ① 版:照定义算 —— 而它稳拿 30 分

p1313Naive.cpp第 ① 版:C(k,n) = k! / (n!·m!),long long 直接算 —— 稳拿 30 分
// ✗ 第 ① 版:所有人真实的第一反应 —— 组合数照定义算 C(k,n) = k! / (n! · m!)
//
// 幂那两下大家都会记得取模(题面明写了要模 10007),栽的是**阶乘**这一头:
// long long 装得下 **20!**(2.43×10¹⁸ < 9.22×10¹⁸),**21! 就是第一个装不下的**。
//
// ★ 所以它不是「一交就零分」—— 题面 30% 那一档写着 `0 ≤ k ≤ 10`,
// 那一整档它算得**一个字不差**。⇒ **这一版稳拿 30 分。**
// ⚠ 到 100% 档 k ≤ 1000 时,k! 有 2568 位,long long 早在第 21 步就绕回去了;
// 而绕回去之后那句整数除法连「除得尽」都不成立 —— 输出的是个看着很正常的垃圾数。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll P = 10007;
static ll qpow(ll a, ll b) {
ll res = 1; a %= P;
while (b) { if (b & 1) res = res * a % P; a = a * a % P; b >>= 1; }
return res;
}
int main() {
ll a, b, k, n, m;
if (scanf("%lld %lld %lld %lld %lld", &a, &b, &k, &n, &m) != 5) return 0;
ll fk = 1, fn = 1, fm = 1;
for (ll i = 1; i <= k; i++) fk *= i; // ⚠ k ≥ 21 就溢出了
for (ll i = 1; i <= n; i++) fn *= i;
for (ll i = 1; i <= m; i++) fm *= i;
ll C = fk / (fn * fm); // ⚠ 溢出之后这句连整除都不成立
printf("%lld\n", (((C % P) + P) % P) * qpow(a, n) % P * qpow(b, m) % P);
return 0;
}
点一下即可编辑
输入(stdin)
输出
点「运行 ▶」看结果
★ 它那条线精确在 k = 21,而题面 30% 那一档是 k ≤ 10

long long 装得下 20! = 2 432 902 008 176 640 000(< 9.22×10¹⁸), 21! 是第一个装不下的。度量程序把 k = 0 … 40 每个 n 都试了一遍: 第一个算错的 k 就是 21

⇒ 题面 30% 那一档写着 0 ≤ k ≤ 10 —— 它在那一整档一个字都不差「暴力值多少分」是「暴力 × 那道题分档」的属性 的又一次。

⚠ 而溢出之后不只是「数大了」:fk / (fn * fm)整数除法fk 一绕回去,连「除得尽」都不成立了 —— 输出的是个看着完全正常的垃圾数。

3第 ② 版:知道要取模了,可最后那一下还是除法

p1313Div.cpp✗ 第 ② 版:阶乘每步取模 —— 但组合数那一下写成了除法
★★ 这是本章第 5 步那句话的考场版:取模之下不能除

fac[k] % p 之后,它和 fac[n]·fac[m] 之间的整除关系整个没了 —— 「先取模再整除」和「先整除再取模」不是一回事,甚至连商是不是整数都不一定。

⇒ 正确的做法是把「除以 x」换成「乘以 x 的逆元」,而 10007 是质数 ⇒ 逆元 = x^(p−2) mod p(费马小定理)。

⚠ 而它样例照过:样例的 k = 3,三个阶乘都还没碰到模数,那句除法碰巧还是真除法。

4★ 第 ③ 版:杨辉三角 —— 这一版就已经能 AC 了

p1313Pascal.cpp★ 第 ③ 版:杨辉三角递推 —— AC,而且这就是该交的那一版
// ★ 第 ③ 版:杨辉三角递推 —— **这一版就已经能 AC 了**
//
// 本章第 3 步那份 brute.cpp 原样搬过来:C(i,j) = C(i−1,j−1) + C(i−1,j),
// 全程只有加法 ⇒ **不用逆元、不用快速幂、连「p 是不是质数」都不用问**。
//
// k ≤ 1000 ⇒ 三角一共 k(k+1)/2 ≈ 50 万个格子,本机不到 1 毫秒(时限 1 秒)。
// ⇒ ★ 这道题只问**一次**,所以那套 O(k) 预处理 + O(1) 回答的模板在这儿一分钱都不值 ——
// 它是给下一道题(多组询问的 P3807)准备的。
//
// ⚠ 但 a^n、b^m 那两下还是要快速幂(n、m 到 1000,硬乘 1000 次也行,只是没必要)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll P = 10007;
static ll qpow(ll a, ll b) {
ll res = 1; a %= P;
while (b) { if (b & 1) res = res * a % P; a = a * a % P; b >>= 1; }
return res;
}
static ll C[1005][1005];
int main() {
ll a, b, k, n, m;
if (scanf("%lld %lld %lld %lld %lld", &a, &b, &k, &n, &m) != 5) return 0;
for (ll i = 0; i <= k; i++) {
C[i][0] = 1;
for (ll j = 1; j <= i; j++) C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % P;
}
printf("%lld\n", C[k][n] * qpow(a, n) % P * qpow(b, m) % P);
return 0;
}
点一下即可编辑
输入(stdin)
输出
点「运行 ▶」看结果
p1313.cpp第 ④ 版:阶乘 + 倒推逆元(本章第 6 步的模板)—— 也 AC,快 76 倍,但这道题用不着
★★ 两种正确写法的账(独占实测,3 次取中位数;顶格 k = 1000,时限 1000 ms)
写法 基本运算 本机 余量
★ 杨辉三角(只有加法) 500 500 次加法 0.47 ms 2143 倍
阶乘 + 倒推逆元 2014 次乘法 0.006 ms 十六万倍

次数少 248.5 倍、秒表快 75.7 倍 —— 而两版都在时限的千分之一以内

⇒ ★★ 这道题该交的是杨辉三角:它只有加法,不问「p 是不是质数」、不用逆元、 不用快速幂,k ≤ 1000 的三角只有 50 万个格子。 那套「O(k) 预处理 + 每次询问 O(1)」的模板是给多组询问准备的, 而这道题只问一次 ⇒ 它在这儿一分钱都不值。

「这个技巧在这道题上成立」和「这道题该用它」是两句话 的又一次。 ★ 那套模板真正派上用场是在下一道题 P3807T 组询问、n+m 到 2×10⁵。

5⚠ 三个错法 —— 而官方样例一个都没挡住

p1313Swap.cpp✗ 错法一:a 和 b 弄反 —— 而它稳拿 50 分
p1313NoModA.cpp✗ 错法二:全用 int,而且快速幂里忘了先 a %= p
p1313Cm.cpp⚠ 不是 bug:把 C(k,n) 写成 C(k,m) —— 答案逐字节相同
★★★ 官方样例是 1 1 3 1 2 —— 它对这一页的五个待测版本全部没有区分度
版本 样例输出 挡住了吗
正解 3
① long long 阶乘 3 ✗ 放过(k = 3,还没溢出)
② 取模之下做除法 3 ✗ 放过(那句除法碰巧还是真除法)
ab 弄反 3 ✗ 放过 —— ★ 样例的 ab 都是 1
int + 忘了 a %= p 3 ✗ 放过(a = 1,平方永远不溢出)
⚠ 用 C(k,m) 3 ✗ 放过(C(3,1) = C(3,2)

「样例是个『一测就死』的过滤器」这条规律的极端情形五个全放过。 ★ 而这一次五个「放过」的原因能一个个说清楚,而且都指向样例里那两个 1

6★★★ 那半行「50% 的数据 a = 1,b = 1」,正是「弄反」的盲区

★★★ 题面 (by + ax)ᵏ 是故意反着写的 —— b 在前,而问的是 xⁿyᵐ

x 配的是 ay 配的是 b,所以系数是 C(k,n) · aⁿ · bᵐ。 可题面把 by 写在前面 ⇒ 顺手一读就成了「第一个数配第一个指数」,写出 aᵐ · bⁿ

★★ 而题面自己给的第二档是 「对于 50% 的数据,有 a = 1b = 1 —— a = b 的时候 aᵐbⁿaⁿbᵐ 恒等

⇒ ★★★ 这个错法交上去稳拿 50 分,而且从输出上完全看不出哪里错了: 出题人那一档不是给暴力留的分,它同时是这个错法的结构性盲区

档位(每档 300 轮) a ≠ b 的轮数 ✗ 弄反真被抓
0 顺手写的(a, b ≤ 100k ≤ 30 297 277
1 照题面随机(a, b ≤ 10⁶ 300 299
⚠⚠ 2 a = b = 1(题面 50% 那一档) 0 精确的 0

★ 档 2 那个 0 是能证的,证明就是那一档的定义;它同时是这个错法的自检 ——同一个动作干两件事:造一档「题面允许而顺手不会造」的数据, 既把 0 证清楚,又称出「a = b = 1」那一档到底护着谁。

7★★ 一个「看着像下标写反、其实恒等」的版本,和它的自检

★★★ C(k, m) 和 C(k, n) 恒等 —— 因为题面写着 n + m = k

C(k, m) = C(k, k−n) = C(k, n)。所以「把 C(k,n) 写成 C(k,m)」这个看着典型的下标手滑, 在这道题上一次都不会错:四个档里三个是精确的 0

★★ 而「一个反例都没有」和「这段代码根本没在跑」在输出上长得一模一样 (第 157 条)⇒ 必须配自检。这一页的自检只要放开题面那句 n + m = k

档位(每档 300 轮) ⚠ 用 C(k,m) 被抓
0 / 1 / 2(题面保证 n + m = k 0 / 0 / 0
⚠ 3 违反题面nm 各自随机 296 / 300

⇒ ★★★ 同一个动作干了两件事:① 证明这段代码是活的; ② 称出 n + m = k 是这一版的命门 —— 去掉它,「用哪个下标」立刻是生死之别。

⚠ 顺带说清楚这个 0 的边界:它只保证「组合数那一半」不受影响。 aⁿ · bᵐ 那一半照样是分得清 nm 的 —— 上一节那个 Swap 就是证据。

8★ 生成器:四个档,每个档专治一个版本

p1313Gen.cpp(四档)生成器:顺手写的 / 照题面 / a=b=1 / ⚠ 违反题面
★★ 五个版本 × 四个档:「满足触发条件」和「真被抓」并排放
档位(每档 300 轮) ① 阶乘溢出 ② 模下除法 ✗ 弄反 ✗ int+没取模 ⚠ 用 C(k,m)
0 顺手写的(a,b ≤ 100k ≤ 30 80(触发 87) 186 277(a≠b 297) 0(触发 0) 0
1 照题面(a,b ≤ 10⁶k ≤ 1000 293(触发 295) 292 299(a≠b 300) 298(触发 299) 0
2 a = b = 1(题面 50% 档) 294(触发 294) 294 0a≠b 0) 0(触发 0) 0
⚠ 3 违反题面 n+m=k 299 298 298 298 296

★★★ 三条读得出来的结论:

  1. int 那个错法的触发条件是「两件各自无害的事凑在一起」 —— 只是「忘了 a %= p」,用 long long 存完全没事(a·a = 10¹²,离 9.2×10¹⁸ 还远); 只是「全用 int」,先取过模也完全没事(10006² ≈ 1.0×10⁸ < 2.1×10⁹)。 两件合在一起才炸,而线精确在 a ≥ 4634146341² > 2³¹)—— 和第 18 章 P1516、第 34 章 P2872 一字不差那是 int 的性质,不是这道题的性质。 ⇒ 顺手写的小 a、小 b精确的 0,只有照题面顶到 10⁶ 才抓得到。
  2. 「触发」和「被抓」差多少,只能量 —— 第 ① 版档 0 是 87 触发 / 80 被抓 (另外 7 轮它溢出了却恰好蒙对),档 2 是 294 ≡ 294(一个不差)。 ⇒ 「它算的是另一个量」推不出「它一定和正解不同」 的又一次。
  3. 档 2 那一列有三个精确的 0 —— 而它是题面自己给的一档(50% 的数据 a=b=1)。 ⇒ 「顺手写的档位能同时把好几个 bug 打成 0」 在这里换了个来源: 这一次不是生成器偷懒,是出题人给的档本身就窄。

9★ 哪一版就已经能过了

p1313Count.cpp本页所有数字的出处
// P1313 的度量程序:./p1313Count csv (本页的数字都出自它)
//
// line : ★ 第 ① 版那条溢出线到底在哪 —— 从 k = 0 一路试上去,第一个算错的 k。
// trig : ★ 三个错法各自的**触发条件**在四个档里出现几轮(对照「真被抓」看两层差多少)。
// cost : ★ 杨辉三角 vs 阶乘+逆元:次数差多少倍、秒表差多少(顶格 k = 1000)。
//
// ⚠ 这里**复刻**了 p1313Gen.cpp 的档位逻辑(同一个 mt19937、同一个种子公式)。
// ⚠ 秒表用 steady_clock 在进程内量,每档 3 次取中位数
// ([第 12 章 P1923 那一跤](/sol/p1923/):秒表断言的主语是余量,不是量级)。
#include <bits/stdc++.h>
#include <chrono>
using namespace std;
using namespace std::chrono;
typedef long long ll;
const ll P = 10007;
static ll qpow(ll a, ll b) {
ll res = 1; a %= P;
while (b) { if (b & 1) res = res * a % P; a = a * a % P; b >>= 1; }
return res;
}
static double med3(double a, double b, double c) { return max(min(a, b), min(max(a, b), c)); }
/** 复刻 p1313Gen.cpp */
static void gen(unsigned seed, int mode, ll& a, ll& b, ll& k, ll& n, ll& m) {
mt19937 rng(seed * 1000003u + 20260903u);
if (mode == 0) { a = (ll)(rng() % 101u); b = (ll)(rng() % 101u); k = (ll)(rng() % 31u); }
else if (mode == 2) { a = 1; b = 1; k = (ll)(rng() % 1001u); }
else { a = (ll)(rng() % 1000001u); b = (ll)(rng() % 1000001u); k = (ll)(rng() % 1001u); }
if (mode == 3) { n = (ll)(rng() % (unsigned)(k + 1)); m = (ll)(rng() % (unsigned)(k + 1)); }
else { n = (ll)(rng() % (unsigned)(k + 1)); m = k - n; }
}
/** int 版那个快速幂会不会溢出:把它的每一步都拿 long long 走一遍 */
static bool intPowOverflows(ll a, ll e) {
const ll TOP = 2147483647LL;
ll res = 1;
while (e) {
if (e & 1) { if (res * a > TOP) return true; res = res * a % P; }
if (a * a > TOP) return true;
a = a * a % P;
e >>= 1;
}
return false;
}
static ll fac[2005], inv[2005];
static void prep(ll k) {
fac[0] = 1;
for (ll i = 1; i <= k; i++) fac[i] = fac[i - 1] * i % P;
inv[k] = qpow(fac[k], P - 2);
for (ll i = k; i >= 1; i--) inv[i - 1] = inv[i] * i % P;
}
static ll okAns(ll a, ll b, ll k, ll n, ll m) {
prep(k);
ll C = fac[k] * inv[n] % P * inv[k - n] % P;
return C * qpow(a, n) % P * qpow(b, m) % P;
}
static ll naiveAns(ll a, ll b, ll k, ll n, ll m) {
ll fk = 1, fn = 1, fm = 1;
for (ll i = 1; i <= k; i++) fk *= i;
for (ll i = 1; i <= n; i++) fn *= i;
for (ll i = 1; i <= m; i++) fm *= i;
ll C = fk / (fn * fm);
return (((C % P) + P) % P) * qpow(a, n) % P * qpow(b, m) % P;
}
int main(int argc, char** argv) {
bool csv = (argc > 1 && string(argv[1]) == "csv");
/* ① 第 ① 版那条线:k 从 0 往上,第一个让它算错的 k(每个 k 把 n 全试一遍) */
int firstBad = -1;
for (ll k = 0; k <= 40 && firstBad < 0; k++)
for (ll n = 0; n <= k; n++)
if (naiveAns(7, 11, k, n, k - n) != okAns(7, 11, k, n, k - n)) { firstBad = (int)k; break; }
/* ② 四个档 × 三个触发条件 */
int trigK[4] = {0, 0, 0, 0}, trigOvf[4] = {0, 0, 0, 0}, trigAB[4] = {0, 0, 0, 0};
for (int mode = 0; mode < 4; mode++)
for (int s = 1; s <= 300; s++) {
ll a, b, k, n, m; gen((unsigned)s, mode, a, b, k, n, m);
if (k >= 21) trigK[mode]++; // Naive 溢出
if (intPowOverflows(a, n) || intPowOverflows(b, m)) trigOvf[mode]++; // NoModA 溢出
if (a != b) trigAB[mode]++; // Swap 有机会现形
}
/* ③ 顶格 k = 1000:杨辉三角 vs 阶乘 + 逆元(次数 + 秒表) */
const ll K = 1000;
ll addPascal = K * (K + 1) / 2; // 三角里真正做加法的格子数
ll mulFast = K + K + 14; // 阶乘 K 次 + 倒推 K 次 + 一次快速幂约 14 步
static vector<vector<int>> C;
double msPascal, msFast;
{
double t[3];
for (int r = 0; r < 3; r++) {
auto t0 = steady_clock::now();
C.assign(K + 1, vector<int>(K + 1, 0));
for (ll i = 0; i <= K; i++) { C[i][0] = 1; for (ll j = 1; j <= i; j++) C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % (int)P; }
t[r] = duration<double, milli>(steady_clock::now() - t0).count();
}
msPascal = med3(t[0], t[1], t[2]);
}
{
double t[3];
for (int r = 0; r < 3; r++) {
auto t0 = steady_clock::now();
volatile ll sink = 0;
for (int rep = 0; rep < 100; rep++) { prep(K); sink += fac[K] + inv[K]; }
t[r] = duration<double, milli>(steady_clock::now() - t0).count() / 100.0;
}
msFast = med3(t[0], t[1], t[2]);
}
if (csv) {
printf("firstBad,%d\n", firstBad);
for (int i = 0; i < 4; i++) printf("trigK%d,%d\n", i, trigK[i]);
for (int i = 0; i < 4; i++) printf("trigOvf%d,%d\n", i, trigOvf[i]);
for (int i = 0; i < 4; i++) printf("trigAB%d,%d\n", i, trigAB[i]);
printf("addPascal,%lld\n", addPascal);
printf("mulFast,%lld\n", mulFast);
printf("opsRatio,%.1f\n", (double)addPascal / (double)mulFast);
printf("msPascal,%.3f\n", msPascal);
printf("msFast,%.3f\n", msFast);
printf("msRatio,%.1f\n", msPascal / msFast);
printf("pascalUnderLimit,%.0f\n", 1000.0 / msPascal);
return 0;
}
printf("① 第 ① 版(long long 阶乘)那条溢出线\n");
printf(" k = 0 .. %d 每个 n 都试过 ⇒ 第一个算错的 k = **%d**(因为 21! 装不下 long long)\n", 40, firstBad);
printf(" ⇒ ★ 题面 30%% 那一档是 k ≤ 10 ⇒ **这一版稳拿 30 分**\n");
const char* NAME[4] = {"顺手写的(a,b ≤ 100、k ≤ 30)", "照题面(a,b ≤ 10⁶、k ≤ 1000)",
"a = b = 1(题面 50% 那一档)", "⚠ 违反题面:n + m ≠ k"};
printf("\n② 四个档各 300 轮,三个错法的**触发条件**各出现几轮\n");
for (int i = 0; i < 4; i++)
printf(" 档 %d %-30s k ≥ 21 的 %3d 轮 / int 会溢出的 %3d 轮 / a ≠ b 的 %3d 轮\n",
i, NAME[i], trigK[i], trigOvf[i], trigAB[i]);
printf(" ⇒ ★ 档 2 那两个 0 就是「a = b = 1 ⇒ 弄反了也一样」的证明(题面 50%% 档的形状)\n");
printf("\n③ 顶格 k = 1000:两种正确写法(独占实测,3 次取中位数;时限 1000 ms)\n");
printf(" 杨辉三角 %8lld 次加法 %.3f ms ⇒ 余量 %.0f 倍\n", addPascal, msPascal, 1000.0 / msPascal);
printf(" 阶乘 + 逆元 %8lld 次乘法 %.3f ms ⇒ 次数少 %.1f 倍、秒表快 %.1f 倍\n",
mulFast, msFast, (double)addPascal / (double)mulFast, msPascal / msFast);
printf(" ⇒ ★ 两版都远在时限之内 ⇒ **这道题该交的是杨辉三角**,逆元那套是给下一道题练手的\n");
return 0;
}
点一下即可编辑
输出
点「运行 ▶」看结果
★ 第 ③ 版(杨辉三角)就已经 AC —— 而三个错法各值 30 / 50 / 0 分
版本 交上去 为什么
long long 阶乘 30 分 30% 档是 k ≤ 10,而它的线在 k = 21
② 模下做除法 0 分 除不尽的那一刻就全塌了
ab 弄反 50 分 50% 档写着 a = b = 1
★ ③ 杨辉三角 AC 50 万次加法,0.47 ms
④ 阶乘 + 逆元 AC 快 76 倍,而这道题一分钱用不上

⇒ 这道题真正要学的两件事都不在算法上: 一行二项式定理,以及读懂数据范围那三行在说什么 —— 它们既是「哪个暴力值多少分」的答案,也是「哪个错法能骗过多少分」的答案。