NOIP2018提高组省一冲奖班模测训练(三)
NOIP2018提高组省一冲奖班模测训练(三)
自己按照noip的方式考,只在最后一两分钟交了一次
第一题过了,对拍拍到尾。
第二题不会。考试时往组合计数的方向想,推公式,推了一个多小时,大脑爆炸,还是一直推不出来(然而正解是dp??)
第三题打了暴力
如果是正式比赛的话,就在省一分数线徘徊。
第二题如果能拿一点部分分的话,那省一就比较稳了
正式比赛的话应该部分分会有,这套题的第二题部分分貌似拿不了
讲解讲的非常细,非常清晰。比雅礼集训听的舒服太多太多了。
Anan的派对
对于 100% 的数据, n≤1000
第一行一个正整数n 。 第二行n个整数表示ci。 第三行n个整数表示di。
第一行一个整数最大快乐值。 第二行一个整数表示最佳方案的参加人数。
6 10 10 10 10 10 9 2 2 2 2 2 3
18 3
1000的数据范围一般是n方,最多加两个log
这道题第一反应二分参加人数不就非常好算了吗但是貌似参加人数不满足单调性然后这个思路就pass掉了然后开始绕弯子,想到搜索,想到动规……一直绕了40多分钟……然后突然想到,貌似直接枚举人数复杂度是n方logn的…………相信自己的第一感觉……然后不要凭感觉看会不会超时,要算复杂度……最后1个小时才做完了,排行榜上有人17分钟AC了…… 枚举出人数之后,有两个小优化(不加也能过)(1)排序的复杂度是nlogn,而我们关心的只是前几个人的值,所以可以用nth_element复杂度是O(n)的。可以把n方logn 优化到n方(2)如果有人的值是负数可以直接break,这个人不选还更优
#include<bits/stdc++.h> #define REP(i, a, b) for(register int i = (a); i < (b); i++) #define _for(i, a, b) for(register int i = (a); i <= (b); i++) using namespace std;const int MAXN = 1e3 + 10; int c[MAXN], d[MAXN], t[MAXN], n;int main() {scanf("%d", &n);_for(i, 1, n) scanf("%d", &c[i]);_for(i, 1, n) scanf("%d", &d[i]);int ans1 = 0, ans2 = 0;_for(num, 1, n){_for(i, 1, n) t[i] = c[i] - d[i] * (num - 1);nth_element(t + 1, t + num, t + n + 1, greater<int>());int sum = 0, ok = 1;_for(i, 1, num) {sum += t[i];if(t[i] < 0) { ok = 0; break; }}if(!ok) break;if(ans1 < sum) { ans1 = sum; ans2 = num;}else if(ans1 == sum && ans2 < num) ans2 = num;} printf("%d\n%d\n", ans1, ans2);return 0; }
XYG的蛋糕
一行两个正整数n,m。
一行一个正整数表示方案数998244353取模。
3 2
4
我第一反应数学问题,应该要用到什么组合数之类的。然后就推啊推啊推啊推啊还是没有推出来中间发现有子问题结构,但没有深入去想 看到300的数据范围的时候应该马上反应到正解应该是一个n三方的复杂度正解是dp其实我发现有子问题结构就应该深入去想dp的我们可以发现当矩形切了之后,矩形变小了,就可以利用之前的值可以设dp[i][j]表示i * j的矩形的方案数显然那么我们可以枚举切在哪个位置先考虑横着切,切在k那么方案数是∑dp[k][j] * dp[i-k][j] 1 <= k < i这里用到了乘法原理,两边的矩形是分步的,所以是乘法同理竖着切 ∑dp[i][k] * dp[i][j-k] 1 <= k < k那么根据加法原理,dp[i][j]就是把两个加起来了。 但是这么做有一个问题,会重复计算比如第一刀切第2行,第二刀切第3行和第一刀切第3行,第二刀切第2行刀痕是一样的,但是算了两次这么办呢,我推数学公式的时候也在这卡住了,想不到好的解决方案 这个时候我们想想两层for循环枚举两两之间元素的时候,我们第二层循环j通常是从i+1开始,因为这样不会重复枚举相同的i,j。那么我们可以把这个思想迁移到这道题。如果我们当前是横着切,那么切的这一行以前一定没有横着切过。这样可以保证不重复,竖着切同理怎么实现呢我们可以设dp[i][j][0~2]dp[i][j][1]表示只是横着切的时候的方案 dp[i][j][2]表示只是竖着切的时候的方案
dp[i][j][0]表示横竖都可以切的时候的方案 那么转移方程就是dp[i][j][1] = dp[k][j][2] * dp[i-k][j][0]dp[i][j][2] = dp[i][k][1] * dp[i][j-k][0]dp[i][j][0] = dp[i][j][1] + dp[i][j][2]答案为 dp[n][m][0]
#include<bits/stdc++.h> #define REP(i, a, b) for(register int i = (a); i < (b); i++) #define _for(i, a, b) for(register int i = (a); i <= (b); i++) using namespace std;typedef long long ll; const int MAXN = 300 + 10; const int mod = 998244353; ll dp[MAXN][MAXN][3]; int n, m;int main() {scanf("%d%d", &n, &m);REP(i, 0, 3) dp[1][1][i] = 1;_for(i, 1, n)_for(j, 1, m){if(i == 1 && j == 1) continue;REP(k, 1, i)dp[i][j][1] = (dp[i][j][1] + dp[k][j][2] * dp[i-k][j][0] % mod) % mod;REP(k, 1, j)dp[i][j][2] = (dp[i][j][2] + dp[i][k][1] * dp[i][j-k][0] % mod) % mod;dp[i][j][0] = (dp[i][j][1] + dp[i][j][2]) % mod;}printf("%lld\n", dp[n][m][0]);return 0; }
WZD的洞洞
100%的数据保证n≤100000;
100%的数据保证0<xi,yi≤10000,-10000<wi<10000。
第一行一个整数n,表示有n个礼品。 第二行两个整数a,b,表示这个直角三角形的两个直角边的长度(a为平行于x轴的直角边的长度,b为平行y轴的直角边的长度)。 接下来n行,每行三个整数xi,yi,wi。
仅一个数,表示最大价值。
4 5 5 1 7 100 1 1 2 2 2 99 7 1 100
101
这一题我判断点是不是在三角形内的方式中斜边是用数学中线性规划的方式判断的完美的避开了正解这道题的关键是一个三维偏序问题,但实际上是一个二维偏序问题一个点被另外一个三角形包含有哪些条件?三条边各一个条件两条直角边就是对x和y坐标的限制如果点j被点i的三角形覆盖则有 xj >= xi, yj >= yi这是很显然的那么斜边呢我开始是用线性规划的方法,推出斜边的方程,然后把点带进去如果小于0那就在斜边的下方这么算没有错,但不能带来优化我们要用一个比较麻烦却可以优化的方式来做就是算出每个点到Bx + Ay = 0的距离(A,B如题目所述)那么如果点j被点i的三角形覆盖则有dis[j] - dis[i] <= A * B / sqrt(A * A + B * B)等号右边是三角形斜边上的高这个式子可以拿笔画一下图,就懂了那么我们可以用一个滑动窗口 O(n)的维护这个东西
先按照dis[i]从小到大排序从大到小遍历,也就是逆序每次把当前点的dis加入队列,这个时候队列里面每一个点的dis都是大于当前这个点的dis的因为是按照从大到小加入的那么最先加入的,也就是说现在处于队尾的,dis值就是最大的那么可以判断拿队头(也就是新加入的点)和队尾做判断,看不满满足
dis[r] - dis[l] <= A * B / sqrt(A * A + B * B)不满足就踢掉队尾,然后继续判断新的队尾,直到满足为止 dis的大小解决了,那么x和y呢??我们可以观察出来,按照上述方式遍历,对于当前点i,和之前加入的点j不可能同时满足xi > xj yi > yj反证法。如果满足的话,那么有dis[i] > dis[j]那么j这个点肯定还没有加入。所以对于最坏只满足xi > xj yi > yj 其中一个或者两个都不满足 那么我们把满足其中一个的点的权值去掉。由于两个条件不会有交集用两个树状数组维护就好了 然后有一些细节要注意,见注释
#include<bits/stdc++.h> #define REP(i, a, b) for(register int i = (a); i < (b); i++) #define _for(i, a, b) for(register int i = (a); i <= (b); i++) using namespace std;typedef long long ll; const int MAXN = 1e5 + 10; const int MAXM = 1e4; struct node {int x, y, w;double dis;bool operator < (const node& rhs) const{return dis < rhs.dis;} }s[MAXN]; int q[MAXN], n, A, B;struct Binary_Index_Tree {int f[(MAXN << 1) + 10];Disjoint_Set() { memset(f, 0, sizeof(f)); }inline int lowbit(int x) { return x & (-x); }void add(int x, int p){x += MAXN + 1; //如果下标有负数,在这里改一下就好了,使得下标大于等于1,下标最大要改,数组空间要改for(; x <= (MAXN << 1) + 1; x += lowbit(x)) f[x] += p;}int sum(int x){int res = 0;x += MAXN + 1;for(; x; x -= lowbit(x))res += f[x];return res;} }X, Y;int main() {scanf("%d%d%d", &n, &A, &B);REP(i, 0, n) {scanf("%d%d%d", &s[i].x, &s[i].y, &s[i].w);s[i].dis = (B * s[i].x + A * s[i].y) / sqrt(A * A + B * B);}sort(s, s + n);double dmax = A * B / sqrt(A * A + B * B); //用double,int有误差 int ans = 0, sum = 0, l = 1, r = 0; //注意这里l与r的取值 for(int i = n - 1; i >= 0; i--){sum += s[i].w;q[++r] = i;while(l <= r && s[q[l]].dis - s[q[r]].dis > dmax) //滑动窗口 {sum -= s[q[l]].w;X.add(s[q[l]].x, -s[q[l]].w); Y.add(s[q[l]].y, -s[q[l]].w); l++;}ans = max(ans, sum - X.sum(s[i].x - 1) - Y.sum(s[i].y - 1)); //一定要区分小于和小于等于,小于记得要-1 X.add(s[i].x, s[i].w); Y.add(s[i].y, s[i].w); //做完了之后再把当前点加进去 } printf("%d\n", ans);return 0; }
总结
(1)只要复杂度是对的,直接枚举答案,不一定要二分。
(2)有子问题结构想dp。不重复的思想
(3)三维偏序问题化为二维偏序问题,二维偏序用树状数组为维护
转载于:https://www.cnblogs.com/sugewud/p/9863668.html
NOIP2018提高组省一冲奖班模测训练(三)相关推荐
- 51Nod NOIP2018提高组省一冲奖班模测训练
51Nod NOIP2018提高组省一冲奖班模测训练 NOIP2018提高组省一冲奖班模测训练1 T1 珂朵莉的旅行 T2 奈芙莲的序列 T3 奈芙莲的护符 NOIP2018提高组省一冲奖班模测训练2 ...
- NOIP2018提高组省一冲奖班模测训练2 T3 XYK的音游
10月22日NOIP2018提高组省一冲奖班模测训练2 T3 XYK的音游 题目描述 XYK最近入坑了一个新音游. 游戏界面上有Ñ个并排的按键,当前这首歌有米个鼓点.游戏的玩法是在鼓点的时刻移动鼠标到 ...
- NOIP2018提高组省一冲奖班模测训练(二)
比赛链接 NOIP2018提高组省一冲奖班模测训练(二) 今天发挥正常,昨天不在状态-- 花了很久A了第一题 第二题打了30分暴力 第三题投机取巧输出test1答案(连暴力都不知道怎么打,太弱了) 2 ...
- NOIP2018提高组省一冲奖班模测训练3 T2 XYG的蛋糕
10月27日NOIP2018提高组省一冲奖班模测训练3 T2 XYG的蛋糕 题目描述 XYG要过生日了,他准备了一个n×m的矩形蛋糕请大家吃. 切蛋糕的方法如下:每次选出已经分出的某一个矩形蛋糕,一刀 ...
- NOIP2018提高组省一冲奖班模测训练(一)
比赛链接 https://www.51nod.com/contest/problemList.html#!contestId=72&randomCode=147206 这次考试的题非常有质量 ...
- [51Nod]NOIP2018提高组省一冲奖班模测训练(一)题解
http://www.51nod.com/contest/problemList.html#!contestId=72&randomCode=147206 原题水题大赛.. A.珂朵莉的旅行 ...
- NOIP2018提高组比赛总结
NOIP2018提高组比赛总结 前言 新赛季,依旧有很多失误. 在些许的遗憾和无奈中,NOIP2018,撒花结束 纵观今年的整一场NOIP,有许多值得总结的地方 正文 NOIP2018初赛 第二次参加 ...
- NOIP2018 提高组游记
NOIP2018 提高组游记的重点不是NOIP而是游记!!! 本文分为 4 个部分: 1.关于2017, 以及自己的简介 2.noip2018游记 3.写给高一高二的学弟学妹 4.写给高三的同学和自己 ...
- P5049 [NOIP2018 提高组] 旅行
P5049 [NOIP2018 提高组] 旅行 题意: 一棵树(可能是基环树),从1出发,每到达一个新的点就记录下编号.求一种走法使得记录下来的编号字典序最小. 1≤n≤500000 m=n−1 或 ...
最新文章
- ios5 中文键盘高度变高覆盖现有ui问题的解决方案(获取键盘高度的方法)
- 学习XHTML的强烈欲望、!
- java构造方法 this_Java之构造方法及this、super关键字
- python财务预算分析_财码Python管理会计小实验—营运管理之多维度盈利能力分析...
- wxpython列表控件listctrl设置某行颜色_wxPython ListCtrl:写入彩色纹理
- SaltStack部署
- 【Spring】Spring lazy-init:bean延迟初始化
- PHP - 验证用户名
- 我们不曾向这个世界的庸俗低头
- python打印文档添加条码_使用Python在Excel中批量生成条形码
- php(wap)获取手机号码,WAP获取访客手机号码
- 咖啡馆html报告,咖啡屋调查报告.ppt
- 读《富爸爸穷爸爸》有感
- 石墨计算机,石墨文档电脑版
- 在计算机英语中memory,memory是什么 memory什么意思
- 《freemind中文教程》笔记
- 微信公开课,视频号成主角,机会来了
- 一对一直播交友APP的核心开发要点,小而美的APP出路吗?
- [MATLAB]图形用户界面的设计(按钮控制绘图)
- 面板模型在python上的实现