NOIP2018提高组省一冲奖班模测训练(三)

自己按照noip的方式考,只在最后一两分钟交了一次

第一题过了,对拍拍到尾。

第二题不会。考试时往组合计数的方向想,推公式,推了一个多小时,大脑爆炸,还是一直推不出来(然而正解是dp??)

第三题打了暴力

如果是正式比赛的话,就在省一分数线徘徊。

第二题如果能拿一点部分分的话,那省一就比较稳了

正式比赛的话应该部分分会有,这套题的第二题部分分貌似拿不了

讲解讲的非常细,非常清晰。比雅礼集训听的舒服太多太多了。

Anan的派对

Anan想举办一个派对。

Anan的朋友总共有 n 人。第i个人如果参加派对会得到 ci 的快乐值,除他自己外每多一个人参加他会减少 di 的快乐值。
Anan想让这个派对的总快乐值尽可能大,在这个基础上,能来的人越多越好。
Anan想知道最佳的邀请方案的快乐值与参加人数。
对于 50% 的数据, n≤20 
对于 100% 的数据, n≤1000 

Input
第一行一个正整数n 。
第二行n个整数表示ci。
第三行n个整数表示di。
Output
第一行一个整数最大快乐值。
第二行一个整数表示最佳方案的参加人数。
Input示例
6
10 10 10 10 10 9
2 2 2 2 2 3
Output示例
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的蛋糕

XYG要过生日了,他准备了一个 n×m 的矩形蛋糕请大家吃。

切蛋糕的方法如下:每次选出已经分出的某一个矩形蛋糕,一刀将其切成两个小矩形蛋糕。当然,这一刀可以选择横切或者竖切。最终XYG要把蛋糕切成 n×m 块 1×1 的小蛋糕。
XYG希望你告诉他总共有多少种不同的切法。两个切法不同当且仅当其中一个切法中存在一条刀痕,在另一个切法中不存在。
对于 40% 的数据, n,m≤15 
对于 100% 的数据, n,m≤300 

Input
一行两个正整数n,m。
Output
一行一个正整数表示方案数998244353取模。
Input示例
3 2
Output示例
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的洞洞

WZD有一个形状为直角三角形的洞洞。

平面上有n个物品,每个物品有坐标xi,yi和价值wi,WZD希望用洞洞包含住价值尽可能高的物品。
由于洞洞的构造,其两条边必须平行于坐标轴,且直角在左下方(也就是说,洞洞只能平行移动),并且要求直角必须恰好落在一个物品上。
求洞洞能包含住最大价值为多少的物品。
40%的数据保证n≤5000;
100%的数据保证n≤100000;
100%的数据保证0<xi,yi≤10000,-10000<wi<10000。

Input
第一行一个整数n,表示有n个礼品。
第二行两个整数a,b,表示这个直角三角形的两个直角边的长度(a为平行于x轴的直角边的长度,b为平行y轴的直角边的长度)。
接下来n行,每行三个整数xi,yi,wi。
Output
仅一个数,表示最大价值。
Input示例
4
5 5
1 7 100
1 1 2
2 2 99
7 1 100
Output示例
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提高组省一冲奖班模测训练(三)相关推荐

  1. 51Nod NOIP2018提高组省一冲奖班模测训练

    51Nod NOIP2018提高组省一冲奖班模测训练 NOIP2018提高组省一冲奖班模测训练1 T1 珂朵莉的旅行 T2 奈芙莲的序列 T3 奈芙莲的护符 NOIP2018提高组省一冲奖班模测训练2 ...

  2. NOIP2018提高组省一冲奖班模测训练2 T3 XYK的音游

    10月22日NOIP2018提高组省一冲奖班模测训练2 T3 XYK的音游 题目描述 XYK最近入坑了一个新音游. 游戏界面上有Ñ个并排的按键,当前这首歌有米个鼓点.游戏的玩法是在鼓点的时刻移动鼠标到 ...

  3. NOIP2018提高组省一冲奖班模测训练(二)

    比赛链接 NOIP2018提高组省一冲奖班模测训练(二) 今天发挥正常,昨天不在状态-- 花了很久A了第一题 第二题打了30分暴力 第三题投机取巧输出test1答案(连暴力都不知道怎么打,太弱了) 2 ...

  4. NOIP2018提高组省一冲奖班模测训练3 T2 XYG的蛋糕

    10月27日NOIP2018提高组省一冲奖班模测训练3 T2 XYG的蛋糕 题目描述 XYG要过生日了,他准备了一个n×m的矩形蛋糕请大家吃. 切蛋糕的方法如下:每次选出已经分出的某一个矩形蛋糕,一刀 ...

  5. NOIP2018提高组省一冲奖班模测训练(一)

    比赛链接 https://www.51nod.com/contest/problemList.html#!contestId=72&randomCode=147206 这次考试的题非常有质量 ...

  6. [51Nod]NOIP2018提高组省一冲奖班模测训练(一)题解

    http://www.51nod.com/contest/problemList.html#!contestId=72&randomCode=147206 原题水题大赛.. A.珂朵莉的旅行 ...

  7. NOIP2018提高组比赛总结

    NOIP2018提高组比赛总结 前言 新赛季,依旧有很多失误. 在些许的遗憾和无奈中,NOIP2018,撒花结束 纵观今年的整一场NOIP,有许多值得总结的地方 正文 NOIP2018初赛 第二次参加 ...

  8. NOIP2018 提高组游记

    NOIP2018 提高组游记的重点不是NOIP而是游记!!! 本文分为 4 个部分: 1.关于2017, 以及自己的简介 2.noip2018游记 3.写给高一高二的学弟学妹 4.写给高三的同学和自己 ...

  9. P5049 [NOIP2018 提高组] 旅行

    P5049 [NOIP2018 提高组] 旅行 题意: 一棵树(可能是基环树),从1出发,每到达一个新的点就记录下编号.求一种走法使得记录下来的编号字典序最小. 1≤n≤500000 m=n−1 或 ...

最新文章

  1. ios5 中文键盘高度变高覆盖现有ui问题的解决方案(获取键盘高度的方法)
  2. 学习XHTML的强烈欲望、!
  3. java构造方法 this_Java之构造方法及this、super关键字
  4. python财务预算分析_财码Python管理会计小实验—营运管理之多维度盈利能力分析...
  5. wxpython列表控件listctrl设置某行颜色_wxPython ListCtrl:写入彩色纹理
  6. SaltStack部署
  7. 【Spring】Spring lazy-init:bean延迟初始化
  8. PHP - 验证用户名
  9. 我们不曾向这个世界的庸俗低头
  10. python打印文档添加条码_使用Python在Excel中批量生成条形码
  11. php(wap)获取手机号码,WAP获取访客手机号码
  12. 咖啡馆html报告,咖啡屋调查报告.ppt
  13. 读《富爸爸穷爸爸》有感
  14. 石墨计算机,石墨文档电脑版
  15. 在计算机英语中memory,memory是什么 memory什么意思
  16. 《freemind中文教程》笔记
  17. 微信公开课,视频号成主角,机会来了
  18. 一对一直播交友APP的核心开发要点,小而美的APP出路吗?
  19. [MATLAB]图形用户界面的设计(按钮控制绘图)
  20. 面板模型在python上的实现

热门文章

  1. 巧用 Linux 定时任务
  2. 已10万人集齐,支付宝集五福今日正式开始
  3. 习题3.6 阅读下面程序,分析其执行过程,写出输出结果
  4. java浮点数减法_浮点数的相关运算Java实现
  5. Android 小米应用角标
  6. 基于风光储能和需求响应的微电网日前经济调度(Python代码实现)
  7. Excel如何设置下拉列表
  8. 元宇宙,一场有趣好玩的大冒险已经瞧瞧开始了……
  9. 3大能力升级,云效+钉钉,让研发协作更「敏捷」
  10. fault tolerance中的错误和故障检测(Error and Fault Detection Mechanisms)