2.11~2.12模拟赛
来源:互联网 发布:拍动态图片软件 编辑:程序博客网 时间:2024/06/16 10:58
这一次的模拟赛一句话就是……考的不行……
对外宣称是NOIP的模拟赛,实际上难的……(可能因为我是蒟蒻的原因吧……)
一共6道题,55分(WTF?)
以下是题解……
鸥哨
【题解】
不难发现是一个组合数,于是就开始了一条不归路路——不断求阶乘,不断取模……最后妥妥地爆零!!!
为什么呢?——罪魁祸首就是因为一系列的不断取模……于是知道了一个神奇的“防爆”方法——逆元!
然后就可以通过逆元解决组合数爆炸的问题,最后不断更新答案就可以了!!!
什么是逆元?其实我也不清楚,但是并没有关系,只需要知道几件事情:
1、对于a、m,把同余方程中正整数x的最小值记作a模m的逆元;
2、逆元实际上就是用乘法代替除法;
3、用扩展欧几里得在算最大公约数的同时算出逆元(即:不定方程ax + my == 1的解x、y);
嗯……大抵上就是这些了,不懂扩展欧几里得的话百度吧……不想写了
【代码】
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <cmath>#include <stack>#include <map>#include <vector>#include <queue>#define L 110000#define mod 1000000007#define LL long longusing namespace std; inline LL gi() { char cj = getchar(); LL ans = 0, f = 1; while (cj < '0' || cj > '9') { if (cj == '-') f = -1; cj = getchar(); } while (cj >= '0' && cj <= '9') ans = ans * 10 + cj - '0', cj = getchar(); return f * ans;} LL n, t, w, x, y;LL f[L], inv[L], ans; inline LL C (int n, int m) { if (n < m) return 0; LL res = (f[n] * inv[m]) % mod; res = (res * inv[n - m]) % mod; return res;} inline LL exgcd(LL a, LL b, LL &x, LL &y) { if (b == 0) { x = 1, y = 0; return a; } LL r = exgcd(b, a % b, x, y); LL temp = x; x = y, y = temp - (a / b) * y; return r;} inline LL solve(LL a) { LL x, y; return exgcd(a, mod, x, y) == 1 ? (x + mod) % mod : -1;} int main() { f[0] = 1; for (LL i = 1; i <= 100000; ++i) f[i] = (i * f[i - 1]) % mod; inv[0] = inv[1] = 1; for (LL i = 2; i <= 100000; ++i) inv[i] = solve(i) % mod; for (LL i = 2; i <= 100000; ++i) inv[i] = (inv[i] * inv[i - 1]) % mod; n = gi(), t = gi(), w = gi(); for (int i = 1; i <= n; ++i) { x = gi(), y = gi(); LL d = abs(x - w); LL num = 0; if (t % 2 == 1) { if (d % 2 == 0) continue; LL pos = (t + 1) / 2 + d / 2; num = (ans + C(t, pos - 1)) % mod; } if (t % 2 == 0){ if (d % 2 == 1) continue; LL pos = t / 2 + 1 + d / 2; num = (num + C(t, pos - 1)) % mod; } num = (num * y) % mod; ans = (ans + num) % mod; } printf("%lld\n", ans % mod); return 0;}
【总结】
这道题考试的时候天真的想着简单的杨辉三角,n^2的算法,最后好像还打萎了,部分分都没有拿全
通过这道题大概了解了一些扩展欧几里得求逆元,总之调了很久,才A的
骨牌移动
【题解】
暴力枚,具体看代码
【代码】
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <cmath>#include <stack>#include <map>#include <vector>#include <queue>#define mod 1000000009#define L 10010#define LL long longusing namespace std;inline int gi() { char cj = getchar(); int ans = 0, f = 1; while (cj < '0' || cj > '9') { if (cj == '-') f = -1;cj = getchar(); } while (cj >= '0' && cj <= '9') ans = ans * 10 + cj - '0', cj = getchar(); return f * ans;}int n, m, k, a, b, c, d, x, y;int p[12][L], ans;bool vis[12][L], bj;inline void dfs(int x, int y) { if (!vis[x][y]) ans++, vis[x][y] = 1; else return ; if (y + 2 <= m && p[x][y + 1] == 1) { p[x][y] = p[x][y + 1], p[x][y + 1] = p[x][y + 2]; dfs(x, y + 2); p[x][y + 2] = p[x][y + 1], p[x][y + 1] = p[x][y]; } if (y - 2 >= 1 && p[x][y - 1] == 2) { p[x][y] = p[x][y - 1], p[x][y - 1] = p[x][y - 2]; dfs(x, y - 2); p[x][y - 2] = p[x][y - 1], p[x][y - 1] = p[x][y]; } if (x + 2 <= n && p[x + 1][y] == 3) { p[x][y] = p[x + 1][y], p[x + 1][y] = p[x + 2][y]; dfs(x + 2, y); p[x + 2][y] = p[x + 1][y], p[x + 1][y] = p[x][y]; } if (x - 2 >= 1 && p[x - 1][y] == 4) { p[x][y] = p[x - 1][y], p[x - 1][y] = p[x - 2][y]; dfs(x - 2, y); p[x - 2][y] = p[x - 1][y], p[x - 1][y] = p[x][y]; }}int main() { freopen("move.in", "r", stdin); freopen("move.out", "w", stdout); n = gi(), m = gi(), k = gi(); for (int i = 1; i <= k; ++i) { a = gi(), b = gi(), c = gi(), d = gi(); if (a == c) { if (b + 1 == d) p[a][b] = 1, p[c][d] = 2; else p[a][b] = 2, p[c][d] = 1; } if (b == d) { if (a + 1 == c) p[a][b] = 3, p[c][d] = 4; else p[a][b] = 4, p[c][d] = 3; } } for (x = 1; x <= n; ++x) { for (y = 1; y <= m; ++y) if (!p[x][y]) {bj = 1; break;} if (bj) break; } dfs(x, y); printf("%d\n", ans - 1); return 0;}
【总结】
考试的时候写别的题去了,并没有写这道题,随便输了一个值,最后果断的爆零了
看了一眼题解后,瞬间后悔考试的时候的斜体顺序,直接用数组记录了每个骨牌的方向,直接爆搜就A了,但是需要注意边界,因为边界WA了一次
围圈
【题解】
一道贪心的题
对于圈中的每一个数i,如果他的l[i]、r[i],满足l[i] > i且r[i] > i,那么一定是移除i,并且保留三个数中的最大数,显然是最优的,于是就会想到对于圈中每一个数进行排序,记录自己左边和右边的数,每一次把min(l[i], r[i]) - i加入ans即可
【代码】
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <cmath>#include <stack>#include <map>#include <vector>#include <queue>#define L 100000 + 1000#define LL long longusing namespace std;inline int gi() { char cj = getchar(); int ans = 0, f = 1; while (cj < '0' || cj > '9') { if (cj == '-') f = -1;cj = getchar(); } while (cj >= '0' && cj <= '9') ans = ans * 10 + cj - '0', cj = getchar(); return f * ans;}struct node { int v, l, r;}num[L];LL n, ans, id[L];inline bool comp (int a, int b) { return num[a].v < num[b].v;}int main() { freopen("game.in", "r", stdin); freopen("game.out", "w", stdout); n = gi(); for (int i = 1; i <= n; ++i) id[i] = i, num[i].v = gi(), num[i].l = i - 1, num[i].r = i + 1; num[1].l = n, num[n].r = 1; sort(id + 1, id + 1 + n, comp); for (int i = 1; i < n; ++i) { int ind = id[i]; ans += min(num[num[ind].l].v, num[num[ind].r].v) - num[ind].v; num[num[ind].r].l = num[ind].l, num[num[ind].l].r = num[ind].r; } printf("%lld\n", ans); return 0;}
【总结】
这道题考试的时候本来是接近正解了的,但是可能是排序的方式不对(或者打萎了吧)最后并没有得到预期分数
拿到题解后,简单的看了一下发现了排序的问题,在原代码上做了微调就A了
难解的集合
【题解】
又是一道求逆元的题,在第一中已经用过了扩展欧几里得,所以这道题用一用费马小定理
费马小定理具体的内容很混乱(反正我没怎么懂),但是核心部分很简单:假如p是质数,且gcd(a,p)=1,那么 a(p-1)≡1(mod p)
对于这道题,不难发现满足组合数,不妨假设f(x)指向p,即最终所有的元素的函数值的函数值等于p
如果已经满足l个f(x)指向了p,那么显然是求从n - 1个数中取l - 1数的组合数,因为数p以确定被取,所以n,l都要减去1,而对于剩下的n - l个数也要在l - 1个数中取,于是将两个方案数相乘加入答案即可,但注意此时的答案是针对一个数的,最后有n个数,所以不要忘记乘以n
【代码】
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <cmath>#include <stack>#include <map>#include <vector>#include <queue>#define L 101000#define LL long long#define mod 1000000007using namespace std;inline LL gi() { char cj = getchar(); int ans = 0, f = 1; while (cj < '0' || cj > '9') { if (cj == '-') f = -1;cj = getchar(); } while (cj >= '0' && cj <= '9') ans = ans * 10 + cj - '0', cj = getchar(); return f * ans;}LL n, fac[L], ans;inline LL inv(LL a, LL b) { if (a < 0 || b < 0) return 0; LL w = 1; for (; b; b >>= 1, a = (LL)a * a % mod) if (b & 1) w = (LL)w * a % mod; return w;}int main() { freopen("set.in", "r", stdin); freopen("set.out", "w", stdout); n = gi(); fac[0] = 1; for (LL i = 1; i <= n; ++i) fac[i] = (LL)fac[i - 1] * i % mod; for (LL l = 1; l <= n; ++l) { LL C1 = (LL)fac[n - 1] * inv(fac[l - 1], mod - 2) % mod * inv(fac[n - l], mod - 2) % mod; LL C2 = (LL)inv(l - 1, n - l); ans = ans + (LL)C1 * C2 % mod, ans %= mod; } ans = (LL)ans * n % mod; printf("%lld\n", ans); return 0;}
【总结】
对于这道题目,考试的时候并没有想到关于组合数、逆元、费马小定理之类一系列高大上的东西,于是就好不犹豫的打了一个n^n的表,最后20分
后面拿到题解后对于l分情况讨论不是很懂,于是就开始手玩(手玩是一个好东西啊),最后还是搞出来了,不过第一次用lemon测的时候ans忘记乘以n了,WA了一次,不过很快就调了出来
- 2.11~2.12模拟赛
- 模拟赛
- 模拟赛~~
- 17.7.7 NOIP模拟赛 【模拟/数据结构】【模拟】
- 【模拟】【程序】2015.8.1noip模拟赛
- Loi 模拟赛 贪心+模拟+DP+数论
- 模拟赛总结。
- Vijos模拟赛
- 模拟赛 数列
- 模拟赛 无线通讯网
- 模拟赛 上白泽慧音
- 模拟赛 东风谷早苗
- 模拟赛 某种密码()
- 模拟赛 牛宫
- noip模拟赛 双城记
- 模拟赛 排队
- 【noip模拟赛】密码
- 模拟赛第一题
- springmvc流程大致分析4 DispatcherServlet请求转发
- 5分钟实现Android中更换头像功能
- NYOJ 995 硬币找零
- D001-开发工具-SecureCRT
- 常见DES实现陷阱
- 2.11~2.12模拟赛
- java反编译后报错的解决办法
- 贝叶斯垃圾邮件分类问题中联合概率的推导
- 基于ROS平台的移动机器人-4-通过ROS利用键盘控制小车移动
- leetcode 500 keyboard row
- iOS开发tips-UITableView、UICollectionView行高/尺寸自适应
- [BZOJ4066]简单题(kd-tree)
- 第38篇 一对多自由控制语音(十八)及PHP实例- AJAXRSS 阅读器
- Maven教程学习网站