HNOI2011解题报告
2017-05-19 21:12
218 查看
HNOI2011解题报告
Author: Pengyihao
Day1 T1 数学作业
题意
给出正整数 n, m,要求将 1−n 这 n 个数连接起来,问连接起来的数对 m 取模的结果是多少。1≤n≤1018,1≤m≤109
思路
如果连接的数的位数一样,那么可以用矩阵乘法进行优化。因为有nowans=lastans∗10k+now
这个恒定的递推式(对于位数一样的数),所以可以分段矩阵乘法。
因为只有 lg(n) 个位数,所以可以解决这个问题。
代码
#include <bits/stdc++.h> typedef long long LL; #define FOR(i, a, b) for (LL i = (a), i##_END_ = (b); i <= i##_END_; i++) #define REP(i, a, b) for (LL i = (a), i##_END_ = (b); i >= i##_END_; i--) template <typename Tp> void in(Tp &x) { char ch = getchar(); x = 0; while (ch < '0' || ch > '9') ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); } template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;} template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;} template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;} template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;} LL n; LL m; LL ten[20]; LL tmpans; LL ret[4][4], tmp[4][4]; void mul(LL x[4][4], LL y[4][4], LL z[4][4]) { LL t[4][4]; memset(t, 0, sizeof t); FOR(i, 1, 3) FOR(j, 1, 3) FOR(k, 1, 3) t[i][j] = (t[i][j] + 1ll * x[i][k] * y[k][j] % m) % m; memcpy(z, t, sizeof t); } bool work(LL x) { bool flagend = false; LL ci = ten[x] - ten[x - 1], fr = ten[x - 1] % m; if (n < ten[x]) { ci = n - ten[x - 1] + 1; flagend = true; } memset(ret, 0, sizeof ret); FOR(i, 1, 3) ret[i][i] = 1; memset(tmp, 0, sizeof tmp); tmp[1][1] = 1; tmp[1][2] = 1; tmp[2][2] = 1; tmp[2][3] = 1; tmp[3][3] = ten[x] % m; while (ci) { if (ci & 1) mul(ret, tmp, ret); mul(tmp, tmp, tmp); ci >>= 1; } tmpans = ( 1ll * ret[1][3] % m + 1ll * fr * ret[2][3] % m + 1ll * tmpans * ret[3][3] % m ) % m; if (flagend) { printf("%lld\n", tmpans); return true; } return false; } int main() { freopen("homework.in", "r", stdin); freopen("homework.out", "w", stdout); in(n); in(m); ten[0] = 1; FOR(i, 1, 18) ten[i] = ten[i - 1] * 10; FOR(i, 1, 18) if (work(i)) break; return 0; }
Day1 T2 勾股定理
这个题目有点问题,我在网上看题解的时候,发现这题的做法其实是不靠谱的,意思是说这是一道玄学的题目。对于题目所给的数据范围,标程不一定都能在合理的时间内跑出答案。
所以我就跳过了这道题目。
Day1 T3 赛车游戏
思路
首先可以用拉格朗日乘数法证明,如果要达到最优成绩,那么每条路上的速度要尽可能相等。于是就可以二分这个速度,然后计算耗油量。
注意如果某条路上耗油量为负数,那么就不能在这条路上用当前二分的速度来计算,因为可能耗油量为负数。
所以我们可以把这条路上的速度设置为令耗油量为0的速度。
这样就可以正确地计算耗油量和跑的时间了。
代码
#include <bits/stdc++.h> typedef long long LL; #define FOR(i, a, b) for (int i = (a), i##_END_ = (b); i <= i##_END_; i++) #define DNF(i, a, b) for (int i = (a), i##_END_ = (b); i >= i##_END_; i--) template <typename Tp> void in(Tp &x) { char ch = getchar(); x = 0; while (ch < '0' || ch > '9') ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); } template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;} template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;} template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;} template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;} const int MAXN = 10010; int T, n; double a, b, vmax, f; double s[MAXN], k[MAXN], sv[MAXN]; const int LIMITS = 1000; double check(double _v) { double sum = 0; FOR(i, 1, n) { if (_v < sv[i]) { sum = sum + Max(0., a * sv[i] + b * k[i]) * s[i]; } else sum = sum + Max(0., a * _v + b * k[i]) * s[i]; } return sum; } int main() { freopen("race.in", "r", stdin); freopen("race.out", "w", stdout); in(T); while (T--) { scanf("%lf%lf%lf%lf", &a, &b, &vmax, &f); in(n); FOR(i, 1, n) { double x, y; scanf("%lf%lf", &x, &y); x /= 1000.0; y /= 1000.0; s[i] = sqrt(x * x + y * y); k[i] = y / x; if (k[i] < 0) sv[i] = Min(-b * k[i] / a, vmax); else sv[i] = 0; } double l = 0, r = 1000000000; FOR(i, 1, LIMITS) { double mid = (l + r) / 2; if (mid > vmax || check(mid) > f) r = mid; else l = mid; } if (check(l) > f) puts("IMPOSSIBLE"); else { double ret = 0; FOR(i, 1, n) { if (sv[i] > l) ret += s[i] / sv[i]; else ret += s[i] / l; } printf("%.5lf\n", ret); } } return 0; }
Day1 T4 括号修复
思路
首先对于一个括号序列,如何计算它最少需要改多少个括号呢?我们发现如果把可以匹配的括号一层一层去掉,那么最后一定会变成下面这个样子:
))))))))(((((((((
就是左边一连串的括号,右边一连串的括号。
假设左边有 l 个括号,右边有 r 个括号。
那么一共要改
⌊l+12⌋+⌊r+12⌋
个括号。
根据“维修数列”这一题的经验,我们可以用splay来维护括号序列。
用+1表示’(‘,用-1表示’)’,那么左边的括号数量就是从左开始的最小子段和,右边的括号数量就是从右开始的最大子段和。
操作1:直接打标记。
操作2:直接打标记。
操作3:变换一下从左开始的最小、最大子段和,从右开始的最小、最大子段和。
操作4:直接取值。
怎么合并标记呢?
当打区间赋值标记的时候,可以直接清空反转标记。
当打反转标记的时候,要将赋值标记乘上-1。
代码
#include <bits/stdc++.h> typedef long long LL; #define FOR(i, a, b) for (int i = (a), i##_END_ = (b); i <= i##_END_; i++) #define DNF(i, a, b) for (int i = (a), i##_END_ = (b); i >= i##_END_; i--) template <typename Tp> void in(Tp &x) { char ch = getchar(); x = 0; while (ch < '0' || ch > '9') ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); } template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;} template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;} template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;} template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;} template <typename Tp> void swap(Tp &x, Tp &y) {Tp z = x; x = y; y = z;} struct Node { bool isa, ist_dn, isset; Node *ch[2], *fa; int lmax, lmin, rmax, rmin, data, sum, sz, wt_set; void update(); void pushdown(); void rotate(); void splay(Node*); }; const int MAXN = 100010; Node *nul, *rot, *to[MAXN]; int n, m; char str[MAXN]; void push(Node *hr, Node *top) { if (hr != nul) push(hr -> fa, top); if (hr != nul) hr -> pushdown(); } void Node::splay(Node *top) { push(this, nul); if (ch[0] != nul) ch[0] -> pushdown(); if (ch[1] != nul) ch[1] -> pushdown(); while (fa != top) { if (fa -> fa != top) { bool t = (fa -> fa -> ch[0] == fa ? 0 : 1); if (fa -> ch[t] == this) { fa -> rotate(); rotate(); } else rotate(), rotate(); } else rotate(); } if (top == nul) rot = this; } void Node::rotate() { Node *pa = fa; fa = pa -> fa; if (fa != nul) { bool t = (fa -> ch[0] == pa ? 0 : 1); fa -> ch[t] = this; } pa -> fa = this; bool t = (pa -> ch[0] == this ? 0 : 1); pa -> ch[t] = ch[t ^ 1]; if (ch[t ^ 1] != nul) ch[t ^ 1] -> fa = pa; ch[t ^ 1] = pa; pa -> update(); update(); } void Node::update() { if (ch[0] != nul) ch[0] -> pushdown(); if (ch[1] != nul) ch[1] -> pushdown(); sum = data; sz = 1; if (ch[0] != nul) sum += ch[0] -> sum, sz += ch[0] -> sz; if (ch[1] != nul) sum += ch[1] -> sum, sz += ch[1] -> sz; lmin = Min(0, Min(ch[0] -> lmin, ch[0] -> sum + data + ch[1] -> lmin)); rmin = Min(0, Min(ch[1] -> rmin, ch[1] -> sum + data + ch[0] -> rmin)); lmax = Max(0, Max(ch[0] -> lmax, ch[0] -> sum + data + ch[1] -> lmax)); rmax = Max(0, Max(ch[1] -> rmax, ch[1] -> sum + data + ch[0] -> rmax)); } void Node::pushdown() { if (ist_dn) { ist_dn = false; int tlmin = lmin, trmin = rmin; int tlmax = lmax, trmax = rmax; data = -data; sum = -sum; lmin = -tlmax; lmax = -tlmin; rmax = -trmin; rmin = -trmax; wt_set = -wt_set; if (ch[0] != nul) { ch[0] -> ist_dn ^= 1; // if (ch[0] -> isset) // ch[0] -> wt_set = -ch[0] -> wt_set; } if (ch[1] != nul) { ch[1] -> ist_dn ^= 1; // if (ch[1] -> isset) // ch[1] -> wt_set = -ch[1] -> wt_set; } } if (isset) { isset = false; if (ch[0] != nul) ch[0] -> isset = true, ch[0] -> wt_set = wt_set, ch[0] -> ist_dn = false; if (ch[1] != nul) ch[1] -> isset = true, ch[1] -> wt_set = wt_set, ch[1] -> ist_dn = false; data = wt_set; sum = wt_set * sz; lmin = rmin = wt_set < 0 ? wt_set * sz : 0; lmax = rmax = wt_set > 0 ? wt_set * sz : 0; } if (isa) { isa = false; if (ch[0] != nul) ch[0] -> isa ^= 1; if (ch[1] != nul) ch[1] -> isa ^= 1; swap(lmin, rmin); swap(lmax, rmax); swap(ch[0], ch[1]); } } void start() { nul = new Node; nul -> sz = 0; nul -> data = nul -> sum = 0; nul -> isa = nul -> ist_dn = nul -> isset = false; nul -> ch[0] = nul -> ch[1] = nul -> fa = nul; nul -> lmax = nul -> rmax = 0; nul -> lmin = nul -> rmin = 0; } void insert(int now) { to[now] = new Node; if (now == 1) rot = to[now]; to[now] -> sz = 1; to[now] -> isa = to[now] -> isset = to[now] -> ist_dn = false; to[now] -> ch[0] = to[now] -> ch[1] = to[now] -> fa = nul; if (now != 1) to[now] -> fa = to[now - 1], to[now - 1] -> ch[1] = to[now]; to[now] -> data = (str[now] == '(' ? 1 : -1); to[now] -> sum = to[now] -> data; } Node *find_key(int rnk) { Node *x = rot; while (1) { x -> pushdown(); int rrnk = (x -> ch[0] == nul ? 1 : x -> ch[0] -> sz + 1); if (rrnk == rnk) return x; if (rrnk > rnk) x = x -> ch[0]; else { x = x -> ch[1]; rnk -= rrnk; } } } char command[20]; int main() { freopen("brackets.in", "r", stdin); freopen("brackets.out", "w", stdout); in(n); in(m); scanf("%s", str + 1); start(); FOR(i, 1, n) insert(i); DNF(i, n, 1) to[i] -> update(); FOR(i, 1, m) { scanf("%s", command); if (command[0] == 'R') { int x, y; in(x); in(y); scanf("%s", command); Node *hr; if (x == 1 && y == n) hr = rot; if (x == 1 && y != n) { find_key(y + 1) -> splay(nul); hr = rot -> ch[0]; } if (x != 1 && y == n) { find_key(x - 1) -> splay(nul); hr = rot -> ch[1]; } if (x != 1 && y != n) { find_key(x - 1) -> splay(nul); find_key(y + 1) -> splay(rot); hr = find_key(y + 1) -> ch[0]; } hr -> pushdown(); hr -> ist_dn = false; hr -> isset = true; hr -> wt_set = (command[0] == '(' ? 1 : -1); hr -> pushdown(); while (hr -> fa != nul) { hr = hr -> fa; hr -> update(); } } else if (command[0] == 'Q') { int x, y; in(x); in(y); Node *hr; if (x == 1 && y == n) hr = rot; if (x == 1 && y != n) { find_key(y + 1) -> splay(nul); hr = rot -> ch[0]; } if (x != 1 && y == n) { find_key(x - 1) -> splay(nul); hr = rot -> ch[1]; } if (x != 1 && y != n) { find_key(x - 1) -> splay(nul); find_key(y + 1) -> splay(rot); hr = find_key(y + 1) -> ch[0]; } hr -> pushdown(); printf("%d\n", (-(hr -> lmin) + 1) / 2 + (hr -> rmax + 1) / 2); } else if (command[0] == 'S') { int x, y; in(x); in(y); Node *hr; if (x == 1 && y == n) hr = rot; if (x == 1 && y != n) { find_key(y + 1) -> splay(nul); hr = rot -> ch[0]; } if (x != 1 && y == n) { find_key(x - 1) -> splay(nul); hr = rot -> ch[1]; } if (x != 1 && y != n) { find_key(x - 1) -> splay(nul); find_key(y + 1) -> splay(rot); hr = find_key(y + 1) -> ch[0]; } hr -> isa ^= 1; hr -> pushdown(); } else if (command[0] == 'I') { int x, y; in(x); in(y); Node *hr; if (x == 1 && y == n) hr = rot; if (x == 1 && y != n) { find_key(y + 1) -> splay(nul); hr = rot -> ch[0]; } if (x != 1 && y == n) { find_key(x - 1) -> splay(nul); hr = rot -> ch[1]; } if (x != 1 && y != n) { find_key(x - 1) -> splay(nul); find_key(y + 1) -> splay(rot); hr = find_key(y + 1) -> ch[0]; } hr -> ist_dn ^= 1; hr -> pushdown(); while (hr -> fa != nul) { hr = hr -> fa; hr -> update(); } } } return 0; }
Day2 T1 任务调度
这是一道随机出答案的题目,所以我没有做,直接跳过了。Day2 T2 XOR和路径
思路
这是一个简单的概率DP。因为是XOR,所以我们可以逐位求出期望。
假设当前在处理第 k 位,设 f[i] 表示从 i 到 n 异或值为 1 的概率。
则对于 i 的一个连出去的边所指向的节点 j,如果边权为 1,则对 f[i] 的贡献为
1−f[j]deg[i]
如果边权为 0,则对 f[i] 的贡献为
f[j]deg[i]
最后别忘了 f[n]=0。
代码
#include <bits/stdc++.h> typedef long long LL; #define FOR(i, a, b) for (int i = (a), i##_END_ = (b); i <= i##_END_; i++) #define DNF(i, a, b) for (int i = (a), i##_END_ = (b); i >= i##_END_; i--) template <typename Tp> void in(Tp &x) { char ch = getchar(); x = 0; while (ch < '0' || ch > '9') ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); } template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;} template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;} template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;} template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;} const int MAXN = 110, MAXM = 10010; const double eps = 1e-8; int n, m, cnt, du[MAXN]; int head[MAXN], data[MAXM << 1], nxt[MAXM << 1], flow[MAXM << 1]; double matrix[MAXN][MAXN]; void add(int x, int y, int z) { nxt[cnt] = head[x]; data[cnt] = y; flow[cnt] = z; head[x] = cnt++; if (x != y) {nxt[cnt] = head[y]; data[cnt] = x; flow[cnt] = z; head[y] = cnt++;} } void gauss_george() { FOR(i, 1, n) { double maxv = -1; int maxq; FOR(j, i, n) { if (fabs(matrix[j][i]) > maxv) { maxv = fabs(matrix[j][i]); maxq = j; } } if (fabs(matrix[maxq][i] - maxv) > eps) { assert(0); } if (fabs(matrix[maxq][i]) < eps) continue; FOR(j, 1, n + 1) { double tmp = matrix[i][j]; matrix[i][j] = matrix[maxq][j]; matrix[maxq][j] = tmp; } double chu = matrix[i][i]; FOR(j, 1, n + 1) matrix[i][j] /= chu; FOR(j, 1, n) { if (j != i) { if (fabs(matrix[j][i]) < eps) continue; double chu = matrix[j][i]; FOR(k, 1, n + 1) matrix[j][k] -= matrix[i][k] * chu; } } } } int main() { freopen("xor.in", "r", stdin); freopen("xor.out", "w", stdout); in(n); in(m); memset(head, -1, sizeof head); FOR(i, 1, m) { int u, v, w; in(u); in(v); in(w); add(u, v, w); du[v]++; if (u != v) du[u]++; } double ans = 0; FOR(i, 1, 31) { memset(matrix, 0, sizeof matrix); FOR(j, 1, n - 1) { matrix[j][j] = du[j]; for (int k = head[j]; k != -1; k = nxt[k]) { if (flow[k] & (1 << (i - 1))) { matrix[j][data[k]] += 1.0; matrix[j][n + 1] += 1.0; } else matrix[j][data[k]] -= 1.0; } } matrix = 1; gauss_george(); ans += (1 << (i - 1)) * matrix[1][n + 1] / matrix[1][1]; } printf("%.3lf\n", ans); return 0; }
Day2 T3 数矩形
思路
这又是一道玄学题。我们找到每条线段的中点,然后按照中点为第一关键字,线段的长度为第二关键字进行排序。
然后对于每个线段,暴力找前面所有跟它中点重合且长度相等的线段……
这样就可以过了。
代码
#include <bits/stdc++.h> typedef long long LL; #define FOR(i, a, b) for (int i = (a), i##_END_ = (b); i <= i##_END_; i++) #define DNF(i, a, b) for (int i = (a), i##_END_ = (b); i >= i##_END_; i--) template <typename Tp> void in(Tp &x) { char ch = getchar(), f = 1; x = 0; while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar(); if (ch == '-') ch = getchar(), f = -1; while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= f; } template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;} template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;} template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;} template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;} const int MAXN = 2010; struct Node { LL lenth; int posx, posy, rposx[2], rposy[2]; } pos[MAXN * MAXN]; int n, cnt, x[MAXN], y[MAXN]; LL two(LL x) {return x * x;} bool cmp(const Node &x, const Node &y) { bool t1 = x.posx < y.posx; bool t2 = x.posx == y.posx && x.posy < y.posy; bool t3 = x.posx == y.posx && x.posy == y.posy && x.lenth < y.lenth; return t1 || t2 || t3; } LL abs(LL x) {return x > 0 ? x : -x;} int main() { freopen("rectangle.in", "r", stdin); freopen("rectangle.out", "w", stdout); in(n); FOR(i, 1, n) { in(x[i]); in(y[i]); } FOR(i, 1, n) FOR(j, i + 1, n) { pos[++cnt].posx = x[i] + x[j], pos[cnt].posy = y[i] + y[j]; pos[cnt].lenth = two(x[i] - x[j]) + two(y[i] - y[j]); pos[cnt].rposx[0] = x[i]; pos[cnt].rposx[1] = x[j]; pos[cnt].rposy[0] = y[i]; pos[cnt].rposy[1] = y[j]; } std::sort(pos + 1, pos + cnt + 1, cmp); LL ans = -1; FOR(i, 1, cnt) { for (int j = i - 1; j >= 1 && pos[j].lenth == pos[i].lenth && pos[i].posx == pos[j].posx && pos[i].posy == pos[j].posy; j--) chkmax(ans, abs(2ll * pos[i].rposx[0] * pos[j].rposy[0] - 2ll * pos[i].rposy[0] * pos[j].rposx[0] + 1ll * pos[j].rposx[0] * pos[i].posy - 1ll * pos[j].rposy[0] * pos[i].posx + 1ll * pos[i].posx * pos[i].rposy[0] - 1ll * pos[i].posy * pos[i].rposx[0])); } printf("%lld\n", ans); return 0; }
Day2 T4 卡农
思路
我们可以先算出可以记片段之间顺序的方案数,因为两两不同,所以最后除以 m! 就可以了。设 f[i] 表示前 i 个片段满足题意的方案数。
如果前 i−1 个片段已经决定了,那么第 i 个片段也可以由奇偶关系决定了。
那么答案就为 P(2n−1,i−1) 减去不合法的方案。
这里的 P(2n−1,i−1) 可以递推求。
不合法的方案只有两种可能:
前 i−1 个片段已经满足偶数要求了,那么第 i 个片段必须是空集合,不符合规定。
所以要减去 f[i−1]。
被决定出来的第 i 个片段重复了。
那么与它重复的那个片段有 i−1 个位置可以选择。
并且如果除了这两个片段之外,其它的片段均满足偶数条件,那么这两个片段一定相同。
而这个片段本身也有 2n−1−(i−2) 种可能。
所以要减去 f[i−2]×(i−1)×(2n−1−(i−2))
所以就可以直接求了。
代码
#include <bits/stdc++.h> typedef long long LL; #define FOR(i, a, b) for (int i = (a), i##_END_ = (b); i <= i##_END_; i++) #define DNF(i, a, b) for (int i = (a), i##_END_ = (b); i >= i##_END_; i--) template <typename Tp> void in(Tp &x) { char ch = getchar(); x = 0; while (ch < '0' || ch > '9') ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); } template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;} template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;} template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;} template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;} const int MOD = 100000007; const int MAXN = 1000010; int n, m; LL f[MAXN]; LL power(LL x, LL y) { LL ret = 1; while (y) { if (y & 1) ret = ret * x % MOD; x = x * x % MOD; y >>= 1; } return ret; } int main() { freopen("canon.in", "r", stdin); freopen("canon.out", "w", stdout); in(n); in(m); LL pre = 1, po = (power(2, n) - 1 + MOD) % MOD; pre = pre * po % MOD; po = (po - 1 + MOD) % MOD; f[0] = 1; f[1] = 0; FOR(i, 2, m) { f[i] = pre; f[i] = (f[i] - f[i - 1] + MOD) % MOD; f[i] = (f[i] - f[i - 2] * (i - 1) % MOD * (power(2, n) - 1 - (i - 2)) % MOD + MOD) % MOD; pre = pre * po % MOD; po = (po - 1 + MOD) % MOD; } LL ret = 1; FOR(i, 1, m) ret = ret * i % MOD; printf("%lld\n", f[m] * power(ret, MOD - 2) % MOD); return 0; }
相关文章推荐
- Regional 2011, Asia - Kuala Lumpur 解题报告
- noip2011提高组day1+day2解题报告
- [NOIP2011] 瑞士轮-解题报告
- noip2011解题报告
- [HNOI 2003] 消防局的建立 解题报告(贪心/动规)
- 《阿里巴巴集团杯》2011(春)HIT ACM程序设计竞赛 解题报告
- BZOJ 2527 [Poi 2011] 整体二分 解题报告
- BZOJ2351 [BeiJing2011]Matrix 解题报告【数据结构】【Hash】
- 2011大纽约区域赛试题 Decoding EDSAC Data 解题报告
- NOIP2011 选择客栈 解题报告(DP)
- 北大校赛2011 Word Ladder(C题) 解题报告
- 2011阿里巴巴程序设计公开赛 / 解题报告 8.18
- NOIP2011 mayan游戏 解题报告(搜索)
- [HNOI2012]矿场搭建 解题报告
- [HNOI2012]与非 解题报告
- HCPC 2011 Spring Online Contest解题报告
- Sichuan University Programming Contest 2011 Preliminary(for Non-SCUers) / 解题报告 4.4
- NOIP2011提高组 聪明的质检员(重庆一中高2018级信息学竞赛测验6) 解题报告
- NOIP2011 计算系数 解题报告(数论)
- BZOJ 2435 [Noi 2011] 树DP 解题报告