NOIP2018提高组省一冲奖班模测训练(二)
比赛链接
今天发挥正常,昨天不在状态……
花了很久A了第一题
第二题打了30分暴力
第三题投机取巧输出test1答案(连暴力都不知道怎么打,太弱了)
2585分和4个人并列rank3
还行吧
LXL的雕像

x 可以为任意非负实数。
lxl想在土地上摆尽可能多的雕像,请你告诉他此时 x 的取值应为多少。
- 一行三个正整数表示 l,n,m。
- 一行一个实数 x ,精确到小数点后五位。
- 如果无法摆下雕像,输出-1。
- 2 18 13
- 0.50000
这道题算是复习了拓展gcd解不定方程
我的做法和讲解人不同,是用exgcd做的
我一开始看到这道题,以为是二分
因为当时想到x越小,雕像肯定越多
所以我就去二分x
写完然后发现,貌似x的取值并不连续
我们设雕像的横着有a个,竖着有b个
符合条件的x值只有很少的一部分,对于每个x有唯一的a与b对应。
这个时候我就想去求最大的(a,b)下的x
然后我就去推公式
显然有
al + a(x + 1) = n
bl + b(x + 1) = m
可以求得
x = (n - al) / (a+1)
x = (m - al) / (b+1)
把x消去
即(n - al) / (a+1) = (m - al) / (b+1)
化简可得
a(m + l) - (n + l)b = n - m
这里只有a和b是不知道的
想到了什么?
拓展gcd求不定方程
显然a越大,b也越大
那么可以求出最大的a,然后通过这个a可以求出x,x即答案
那么a的限制条件是什么
显然有a * l < n
那么a < n / l (向下取整)
所以我们可以通过调整解来取得最大的a
最后注意要特判一下n <= l 和 m <= l是无解的,直接输出-1
- #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;
- void exgcd(int a, int b, int& d, int& x, int& y)
- {
- if(!b) { d = a; x = ; y = ; return; }
- else { exgcd(b, a % b, d, y, x); y -= x * (a / b); }
- }
- int main()
- {
- int l, n, m;
- scanf("%d%d%d", &l, &n, &m);
- if(n <= l || m <= l) { puts("-1"); return ; }
- int A, B, K, d, x, y;
- A = m + l, B = -(n + l), K = n - m;
- exgcd(A, B, d, x, y);
- if(K % d != ) { puts("-1"); return ; }
- x *= K / d; int mod = abs(B / d);
- x = (x % mod + mod) % mod;
- int max_x = n / l;
- if(n % l == ) max_x--;
- int t = (max_x - x) / mod;
- x = x + t * mod;
- if(n - x * l <= ) puts("-1");
- else printf("%.6lf\n", ((double)n - x * l) / (x + ));
- return ;
- }
XYK的音游
在 0 时刻xyk可以把鼠标放在任意位置。鼓点出现的时刻大于 0 。保证同一时间不会有两个鼓点。由于这款音游并不看重连击,xyk希望分数尽可能高就好。请你帮助他计算他能获得的最高分数。
对于 50% 的数据, n×m≤106 。
对于 100% 的数据, n,m≤100000,p≤5,ti≤1000000 。
- 第一行三个正整数 n,m,p。
- 接下来 m 行每行三个正整数 t_i,w_i,x_i 描述第 i 个鼓点。
- 一行一个整数表示最大分数。
- 5 5 1
- 2 42 4
- 3 23 4
- 1 70 4
- 2 31 5
- 1 85 5
- 150
觉得第三题比第二题简单一点,先写第三题
考试的时候给这道题留的时间不多
感觉是dp,但是因为时间不多没有深入去想,只想打打暴力
然而最后暴力都没打出来
这一题其实dp方程很好想
50分的数据说明可以有一个O(nm)的做法
可以设f[i]为处理了前i个鼓点,第i个一定选的最高分数
如果按照时间排序的话,那么有
f[i] = w[i] + f[j] (|x[i]-x[j]| <= p(t[i]-t[j]))
如果给我多点时间,我估计只能想到这
接下来的操作就非常秀了
可以发现,如果不按照时间排序,就按照输入的顺序,这个方程仍然成立
f[i] = w[i] +max(f[j]) (|x[i]-x[j]| <= p(t[i]-t[j]))
因为如果j的时间大于i的时间,那么这个条件 (|x[i]-x[j]| <= p(t[i]-t[j]))不可能成立
也就是说这个方程已经把按照时间排序这一步给省掉了。
那么我们是不是可以排其他东西来优化呢?
目前还看不出来,我们继续分析
这个做法主要的时间花在求max(f[j])要O(n)的时间
我们能不能优化成O(logn)
我们把绝对值拆开(这一步很骚)
可以得到
-p(t[i]-t[j]) <= x[i] - x[j] <= p(t[i]-t[j])
这里i和j是混在一起的,我们试着把i放在不等式的一边,j放在不等式的另外一边
-p(t[i]-t[j]) <= x[i] - x[j]
变成
pt[j] + x[j] <= pt[i] + x[i]
同样
p(t[i]-t[j]) >= x[i] - x[j]
变成
pt[i]-x[i]>=pt[j]-x[j]
那么
对于pt[i]-x[i]>=pt[j]-x[j],可以一开始排序完成
对于pt[j] + x[j] <= pt[i] + x[i],用树状数组优化,把pt[i] + x[i]当作下标,dp值作为值
和用树状数组求LIS的思路很像
那么这道题就可以优化到nlogn了。
注意排序的时候如果第一个条件相等,就排第二个条件。否则会WA5个点(在这卡了好久)
- #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 = 1e5 + ;
- int f[MAXN], dp[MAXN], b[MAXN];
- int n, m, p, N, ans;
- struct node
- {
- int t, w, x, k;
- bool operator < (const node& rhs) const
- {
- return p * t - x < p * rhs.t - rhs.x || p * t - x == p * rhs.t - rhs.x && p * t + x < p * rhs.t + rhs.x;
- }
- }a[MAXN];
- void read(int& x)
- {
- int f = ; x = ; char ch = getchar();
- while(!isdigit(ch)) { if(ch == '-') f = -; ch = getchar(); }
- while(isdigit(ch)) { x = x * + ch - ''; ch = getchar(); }
- x *= f;
- }
- inline int lowbit(int x) { return x & (-x); }
- void motify(int x, int p)
- {
- for(; x <= N; x += lowbit(x))
- f[x] = max(f[x], p);
- }
- int get_max(int x)
- {
- int res = ;
- for(; x; x -= lowbit(x))
- res = max(res, f[x]);
- return res;
- }
- int main()
- {
- read(n); read(m); read(p);
- REP(i, , m)
- {
- read(a[i].t), read(a[i].w), read(a[i].x);
- a[i].k = p * a[i].t + a[i].x;
- }
- sort(a, a + m);
- _for(i, , m) b[i] = a[i].k;
- sort(b, b + m);
- N = unique(b, b + m) - b;
- REP(i, , m) a[i].k = lower_bound(b, b + N, a[i].k) - b + ;
- REP(i, , m)
- {
- dp[i] = get_max(a[i].k) + a[i].w;
- ans = max(ans, dp[i]);
- motify(a[i].k, dp[i]);
- }
- printf("%d\n", ans);
- return ;
- }
ZYZ的游戏
zyz希望得到的森林中的最长路径尽可能小。zyz当然知道啦,但他想考考你这个最小值是多少。
对于 60% 的数据, n,k≤50000 。
对于 100% 的数据, n,k≤400000 。
- 第一行两个整数 n,k。
- 接下来 n-1 行,每行两个正整数 x,y ,描述一条树边 (x,y)。
- 一行一个整数,最长路径的表示最小值。
- 6 2
- 1 2
- 1 3
- 1 4
- 2 5
- 3 6
- 1
- 比赛的时候打了个30分暴力
- #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 = 4e5 + ;
- struct Edge{ int to, next, w; };
- Edge e[MAXN<<];
- int head[MAXN], tot, o, cnt;
- int vis[MAXN], n, m, k;
- void read(int& x)
- {
- int f = ; x = ; char ch = getchar();
- while(!isdigit(ch)) { if(ch == '-') f = -; ch = getchar(); }
- while(isdigit(ch)) { x = x * + ch - ''; ch = getchar(); }
- x *= f;
- }
- void AddEdge(int to, int from)
- {
- e[tot] = Edge{to, head[from], };
- head[from] = tot++;
- }
- int dfs(int u)
- {
- vis[u] = ;
- int max1 = , max2 = ;
- for(int i = head[u]; ~i; i = e[i].next)
- {
- int v = e[i].to;
- if(vis[v] || !e[i].w) continue;
- int now = dfs(v) + ;
- if(now > max1) max2 = max1, max1 = now;
- else if(now > max2) max2 = now;
- }
- cnt = max(cnt, max1 + max2);
- return max1;
- }
- int num(int x) { return !x ? : + num(x & (x - )); }
- int main()
- {
- memset(head, -, sizeof(head)); tot = ;
- read(n); read(k); m = n - ;
- REP(i, , m)
- {
- int u, v;
- read(u); read(v); u--; v--;
- AddEdge(u, v); AddEdge(v, u);
- }
- int ans = 1e9;
- REP(S, , << m)
- {
- if(num(S) != k) continue;
- REP(i, , m)
- {
- if(S & ( << i))
- {
- e[ * i].w = ;
- e[ * i + ].w = ;
- }
- else
- {
- e[ * i].w = ;
- e[ * i + ].w = ;
- }
- }
- int t = ;
- memset(vis, , sizeof(vis));
- REP(i, , n)
- if(!vis[i])
- {
- cnt = ;
- dfs(i);
- t = max(t, cnt);
- }
- ans = min(ans, t);
- }
- printf("%d\n", ans);
- return ;
- }
这道题还是很精彩的。
首先最长路径尽可能小可以想到二分答案(智障的我没有想到,对二分不够敏感)
对于每一个二分值ans可以做一次树形dp
每次把路径长度要超过ans的子树删掉
这里有个小优化,可以O(n)完成这个过程
把子树的路径分为大于ans/2以及小于等于ans/2的
如果是大于ans / 2,只留下一个,因为如果大于等于两个,加起来就会大于ans
对于小于等于ans/2的全部留下,同时记录此时最长路径
那么最后要考虑要不要打大于ans/2的剩下的那一个删掉
我们就比较大于ans/2里面剩下的(也就是最小的)和小于等于ans/2最大的加起来
看有没有大于ans,如果大于,那么剩下的唯一一个的大一ans/2的就也要删掉
这样就可以O(n)的维护这个过程。
如果不这么做的话就只能排序来比较,复杂度是O(logn)
所以二分O(logn),树形dp O(n),总复杂度O(nlogn)
注意一定要在纸上画图想清楚每一个细节,然后就可以一遍AC了
- #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 = 4e5 + ;
- struct Edge{ int to, next; };
- Edge e[MAXN << ];
- int head[MAXN], dp[MAXN], d[MAXN], tot;
- int n, m, k;
- void read(int& x)
- {
- int f = ; x = ; char ch = getchar();
- while(!isdigit(ch)) { if(ch == '-') f = -; ch = getchar(); }
- while(isdigit(ch)) { x = x * + ch - ''; ch = getchar(); }
- x *= f;
- }
- void AddEdge(int to, int from)
- {
- e[tot] = Edge{to, head[from]};
- head[from] = tot++;
- }
- void dfs(int u, int fa, int ans)
- {
- int cnt = , mind = 1e9, maxd = ;
- for(int i = head[u]; ~i; i = e[i].next)
- {
- int v = e[i].to;
- if(v == fa) continue;
- dfs(v, u, ans);
- dp[u] += dp[v];
- if(d[v] + > ans / )
- {
- cnt++;
- mind = min(mind, d[v] + );
- }
- else maxd = max(maxd, d[v] + );
- }
- if(cnt)
- {
- if(mind + maxd > ans) dp[u] += cnt, d[u] = maxd;
- else dp[u] += cnt - , d[u] = mind;
- }
- else d[u] = maxd;
- }
- bool check(int ans)
- {
- memset(dp, , sizeof(dp));
- memset(d, , sizeof(d));
- dfs(, -, ans);
- return dp[] <= k;
- }
- int main()
- {
- memset(head, -, sizeof(head)); tot = ;
- read(n); read(k);
- REP(i, , n)
- {
- int u, v;
- read(u); read(v);
- AddEdge(u, v); AddEdge(v, u);
- }
- int l = -, r = n - ;
- while(l + < r)
- {
- int m = (l + r) >> ;
- if(check(m)) r = m;
- else l = m;
- }
- printf("%d\n", r);
- return ;
- 总结
(1)拓展gcd,无解特判
(2)二分答案,树形dp,ans/2优化
(3)dp,排序,拆绝对值,树状数组优化
NOIP2018提高组省一冲奖班模测训练(二)的更多相关文章
- NOIP2018提高组省一冲奖班模测训练(六)
NOIP2018提高组省一冲奖班模测训练(六) https://www.51nod.com/Contest/ContestDescription.html#!#contestId=80 20分钟AC掉 ...
- NOIP2018提高组省一冲奖班模测训练(五)
NOIP2018提高组省一冲奖班模测训练(五) http://www.51nod.com/Contest/ContestDescription.html#!#contestId=79 今天有点浪…… ...
- NOIP2018提高组省一冲奖班模测训练(四)
NOIP2018提高组省一冲奖班模测训练(四) 这次比赛只AC了第一题,而且花了40多分钟,貌似是A掉第一题里面最晚的 而且还有一个半小时我就放弃了…… 下次即使想不出也要坚持到最后 第二题没思路 第 ...
- NOIP2018提高组省一冲奖班模测训练(三)
NOIP2018提高组省一冲奖班模测训练(三) 自己按照noip的方式考,只在最后一两分钟交了一次 第一题过了,对拍拍到尾. 第二题不会.考试时往组合计数的方向想,推公式,推了一个多小时,大脑爆炸,还 ...
- NOIP2018提高组省一冲奖班模测训练(一)
比赛链接 https://www.51nod.com/contest/problemList.html#!contestId=72&randomCode=147206 这次考试的题非常有质量 ...
- [51Nod]NOIP2018提高组省一冲奖班模测训练(三) 题解
链接 A.Anan的派对 题意:Anan想举办一个派对.Anan的朋友总共有 n 人.第i个人如果参加派对会得到 \(c_i\) 的快乐值,除他自己外每多一个人参加他会减少 \(d_i\) 的快乐值. ...
- [51Nod]NOIP2018提高组省一冲奖班模测训练(四)翻车记+题解
链接 下午5点的时候,突然想起来有这个比赛,看看还有一个小时,打算来AK一下,结果因为最近智商越来越低,翻车了,我还是太菜了.上来10分钟先切掉了C和A,结果卡在了B题,唉. A.砍树 一眼题,两遍树 ...
- [51Nod]NOIP2018提高组省一冲奖班模测训练(二)
http://www.51nod.com/contest/problemList.html#!contestId=73&randomCode=4408520896354389006 还是原题大 ...
- [51Nod]NOIP2018提高组省一冲奖班模测训练(一)题解
http://www.51nod.com/contest/problemList.html#!contestId=72&randomCode=147206 原题水题大赛.. A.珂朵莉的旅行 ...
随机推荐
- Vue.js 渲染简写样式存在的问题
引出问题 首先我们来这么一个问题, 这里是完整的 jsfiddle demo or codepen demo 给一个元素绑定两个边框样式, 右侧和底部都为1px的红色边框 styleA: { bord ...
- BA-siemens-apogee总线不稳定解决方法
状况一:BLN下的火车头在线,但是下面的模块(包括UEC或者PPM)全部掉线 尝试方法: 使用挨个DDC箱断线的方法测试总线是否上线(可以解决由于总线短路引起的总线故障,施工中总线压冷压端子的话就不容 ...
- Cocos2d-x 动手实现游戏主循环
因为Cocos2d-x封装的非常好,所以对于非常多新手,他们仅仅知道先new一个场景,在场景上加入布景或精灵,然后用Director的runWithScene便能够执行游戏了.假设给一个精灵加个动作, ...
- 积跬步,聚小流------Bootstrap学习记录(1)
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/ ...
- unity3d Pathfinding插件使用
Overview The central script of the A* Pathfinding Project is the script 'astarpath.cs', it acts as a ...
- 【MySQL】MySQL删除匿名用户,保证登录安全
博客地址已迁往 www.virtclouds.com 原文地址 http://www.virtclouds.com/538.html 很多MySQL程序都会带有匿名登录的功能. 在刚刚安装完MySQL ...
- Ubuntu14.04下初步使用MongoDB
不多说,直接上干货! Ubuntu14.04下Mongodb(在线安装方式|apt-get)安装部署步骤(图文详解)(博主推荐) shell命令模式 输入mongo进入shell命令模式,默认连接的数 ...
- mybatis的sql语句导致索引失效,使得查询超时
mybaitis书写sql需要特别注意where条件中的语句,否则将会导致索引失效,使得查询总是超时.如下语句会出现导致索引失效的情况: with test1 as (select count(C_F ...
- 后台通过Request取得多个含有相同name的控件的值
string[] arrWeight = context.Request.Params.GetValues("Quantity");
- python爬虫:爬取医药数据库drugbank
这个是帮朋友做的,难点就是他们有一个反爬虫机制,用request一直不行,后面我就用selenium直接把网页copy下来,然后再来解析本地的html文件,就木有问题啦. 现在看来,写得有点傻,多包涵 ...