一篇来自ACM入门者的补题记录

文章目录

  • A.机器人
  • B.吃豆豆
  • C.拆拆拆数
  • E.流流流动
  • F.爬爬爬山
  • I.起起落落
  • J.夺宝奇兵

A.机器人

题意:有两条平行线段A,B,长度从1~n,机器人一开始位于A线段的s点,有r个目标点分布在两个线段上,同时存在m个特殊点,1,n是两个特殊点,机器人只能在特殊站点完成调头、区域间的转换,问机器人经过所有目标点并回到起点,需要的最短时间?

思路:因为起点与终点是同一个点,肯定需要画一个矩形把两个线段上离1点最近的目标点,和离n点最近的目标点给框起来(因为1,n是特殊点,这样的矩形必然存在)在一些情形下还需要画一些别的路线就可以走完所有特殊点。综合结论,只有两个因素值得考虑:

1.特殊点分布在s点的一侧还是两侧:
如果分布在两侧直接画大矩形;如果分布在一侧,考虑s点最远端的目标点,先画一条直路线连接,考虑第二个因素。

2.B线段是否存在目标点:
如果不存在,机器人在到达最远端的目标点以后,会找一个最近的特殊站点调头,重复之前走过的路程就好;如果存在,机器人会在特殊站点转换区域,接下来需要找的是B段离s最近的目标点的特殊点,让机器人通过此站点回到A段上;A段无需特判,B段需要特判,否则有可能让机器人在没有必要的情况下,绕到没有目标点的一端回去。

题目给的数据比计较水,但自己写的代码就是过不了,以下代码参考了别人的写法,lower_bound()和upper_bound()在这题中真的巨好用,别忘了在区域转移时加上转移时间k。

#include<bits/stdc++.h>
using namespace std;
int n,r,m,k,s;
vector<int>A;
vector<int>B;
vector<int>T;
int main()
{scanf("%d%d%d%d%d",&n,&r,&m,&k,&s);for(int i = 0;i<r;i++){int w,flag;scanf("%d%d",&w,&flag);if(flag == 0 && w == s)continue;if(flag == 0)A.push_back(w);else if(flag == 1)B.push_back(w);}T.push_back(1);T.push_back(n);for(int i = 0;i<m;i++){int w;scanf("%d",&w);T.push_back(w);}sort(T.begin(),T.end());sort(A.begin(),A.end());sort(B.begin(),B.end());int ans = 0;int lb,rb;if(B.empty() && A.empty()){cout<<0<<endl;return 0;}int MIN = 0x3f3f3f3f;int MAX = 0;if(!A.empty()){MIN = min(MIN,A[0]);MAX = max(MAX,A[A.size()-1]);}if(!B.empty()){lb = B[0];rb = B[B.size()-1];MIN = min(MIN,B[0]);MAX = max(MAX,B[B.size()-1]);}if(s <= MIN ){int s1 = *(lower_bound(T.begin(),T.end(),MAX));ans = s1 - s;if(!B.empty()){int s2 = *(upper_bound(T.begin(),T.end(),lb)-1);ans += s1 - s2;ans += abs(s2-s);ans += 2*k;}elseans += s1-s;}else if(s >= MAX){int s1 = *(upper_bound(T.begin(),T.end(),MIN)-1);ans = s - s1;if(!B.empty()){int s2 = *(lower_bound(T.begin(),T.end(),MAX));ans += s2 - s1;ans += abs(s-s2);ans += 2*k;}elseans += s - s1;}else{int s1 = *(upper_bound(T.begin(),T.end(),MIN)-1);int s2 = *(lower_bound(T.begin(),T.end(),MAX));ans = 2*(s2-s1);if(!B.empty())ans += 2*k;}cout<<ans<<endl;return 0;
}

B.吃豆豆

题意:n行m列的格子图,对于第i行第j列的格子,会在T[i][j]时刻出现一个糖果,问从S点走到T点,至少拿到C个糖果的最短时间是多少。

思路: d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]代表到达i,j这个点花费k时间能拿到的最大糖果数,则状态转移方程为: d p [ i ] [ j ] [ k ] = m a x dp[i][j][k] = max dp[i][j][k]=max{ d p [ 四 个 方 向 ] [ k − 1 ] dp[四个方向][k-1] dp[四个方向][k−1]} + k + k +k% T [ i ] [ j ] T[i][j] T[i][j] == 0 ? 1 : 0 0 ? 1 : 0 0?1:0;
这是一个需要三重循环处理的dp,i,j的范围显而易见,k的范围考虑题目给了3000ms,n,m<=10,大胆将k设置为10010,找到k最小的 d p [ i ] [ j ] [ k ] &gt; = C dp[i][j][k]&gt;=C dp[i][j][k]>=C就过了…
值得注意初始化要将起点的 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]设置为0,其他的dp值设置为负无穷,以示从这个点开始才能获取到正常的糖果数…

代码不贴了,提一嘴div1的数据范围比div2的大得多,需要使用倍增法blabla…讲解没听太懂,哎…

C.拆拆拆数

题意:读入A,B两个数(5<=A,B<=1e18),把A拆为a1,a2…an,把B拆为b1,b2…bn,使得对于任意i,j∈[1,n],gcd(ai,bj) = 1;输出n最小的一组a与b。

思路:冷静分析一番,如果A,B存在这样分解方法,那么n一定<=2。当A,B互素时,直接输出n=1,A,B;当A,B不是互素的时候,想办法构造这样的一组a,b,很容易就想到了素数表,拿A,B去减同一个素数,如果剩下的数是互素的,就拆解完成了。

这是一道我现场过的题目,把素数表打出来后,随便搜搜就出A了,代码和思路一样很简单,就不贴了…别的博客有真正构造的方法(捂脸…)

D.超难的数学题
暂未补上…

E.流流流动

题意:有1,2,3…n共n个数字。取得数字i会有f[i]的收益。i为奇数时,与3*i+1之间有边,i为偶数时,与i/2之间有边。当一条边上的两点x,y同被取得时,会失去d[min(x,y)]的价值,求问最大收益。

思路:如果能看出这是棵树,这题就很好做了。把所有的边连起来,发现会出现一些三叉结点,处理方法是把三叉结点连接的两棵子树,合并成为同一棵树,用并查集去维护这个森林。因为不知道连接前后父子关系的转变,所以我们需要建立双向边。建好森林以后,从若干个根结点开始,分别进行很裸的树形dp就好了。

小坑点:1,2,4这三个点,4本身是一个三叉结点,但它所连接的子树1,2之间存在有边,建树以后就构成了一个循环节,所以我们在建树的时候需要跳过1这个点,舍弃1,4这条边,然后就能A了…

这是我写的第一道树形dp的题目,还是比较愉快的。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 105;
vector<int>tree[maxn];
vector<int>root;
int dp[maxn][2],f[maxn],d[maxn],ans;
int pre[maxn];
void di(int x,int fa){dp[x][0] = 0;dp[x][1] = f[x];for(int i = 0;i<tree[x].size();i++){int y = tree[x][i];if(y == fa)continue;di(y,x);dp[x][0] += max(dp[y][0],dp[y][1]);dp[x][1] += max(dp[y][0],dp[y][1]-d[min(x,y)]);}
}
int Find(int x){if(x != pre[x])return pre[x] = Find(pre[x]);return x;
}
void init(int n){for(int i = 1;i<=n;i++)pre[i] = i;for(int i = 2;i<=n;i++){if(i % 2 == 1 && i * 3 + 1 <=n){tree[i].push_back(i*3+1);tree[i*3+1].push_back(i);if(Find(i) != Find(i*3+1)){int x = pre[i*3+1];int y = pre[i];pre[x] = y;}}if(i % 2 == 0){tree[i].push_back(i/2);tree[i/2].push_back(i);if(Find(i) != Find(i/2)){int x = pre[i];int y = pre[i/2];pre[x] = y;}}}
}
int main()
{int n;scanf("%d",&n);for(int i = 1;i<=n;i++)scanf("%d",&f[i]);for(int i = 1;i<=n;i++)scanf("%d",&d[i]);init(n);for(int i = 1;i<=n;i++)if(pre[i] == i)root.push_back(i);ans = 0;for(int i = 0;i<root.size();i++){int x = root[i];di(x,x);ans += max(dp[x][0],dp[x][1]);}cout<<ans<<endl;return 0;
}

F.爬爬爬山

一道比较裸的最短路题目,本场训练的签到题,队友做出来了。我还没有写过,不知道以后会不会写…hh…
———————————————————————————————————————
最近复习最短路,把这题给过了。题意比较裸,就是在爬山的时候考虑体力的变化,若体力不足则使用降低山高度的操作。因为每座山的高度只能被降低一次,所以我们只有在以一座山作为最短路起点时,才更新山的高度,需要记录一下这座山的高度是否发生过改变。

注意数据需要开 long long ,以及 n <=1e5,普通版本的迪杰特斯拉是过不了的,需要堆优化也就是优先队列版本的。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
const long long INF = 1e18;
int height[maxn];
long long dis[maxn],fis[maxn],rest[maxn];
bool vis[maxn];
int n,m,k;
struct edge{int next,w;edge(int a,int b){next = a;w = b;}
};
vector<edge>G[maxn];
struct D{int u;long long d;D(int a,long long b){u = a;d = b;}
};
struct cmp{bool operator()(D X,D Y){return X.d > Y.d;}
};
long long di(){for(int i = 1;i<=n;i++){fis[i] = 0;vis[i] = false;dis[i] = INF;}priority_queue<D,vector<D>,cmp> U;rest[1] = k;dis[1] = 0;U.push(D(1,0));while(!U.empty()){int u = U.top().u;long long d = U.top().d;U.pop();if(dis[u] < d)continue;if(u == n)return d;vis[u] = true;height[u] -= fis[u];int len = G[u].size();for(int i = 0;i<len;i++){int v = G[u][i].next;int qe = G[u][i].w;if(vis[v])continue;long long lo,nk,l = 0;if(height[v]<=height[u]+rest[u]){lo = 1ll*qe;nk = height[u]+rest[u]-height[v];}else{l = height[v]-height[u]-rest[u];lo = qe+l*l;nk = 0;}if(lo + d < dis[v]){fis[v] = l;dis[v] = lo + d;rest[v] = nk;U.push(D(v,dis[v]));}}}
}
int main()
{scanf("%d%d%d",&n,&m,&k);for(int i = 1;i<=n;i++)scanf("%d",&height[i]);for(int i = 0;i<m;i++){int x,y,z;scanf("%d%d%d",&x,&y,&z);G[x].push_back(edge(y,z));G[y].push_back(edge(x,z));}long long ans = di();printf("%lld\n",ans);return 0;
}

G.双重矩阵
暂未解决。

H.我爱割葱
据说是一道比较难的区间dp题目,区间dp的题目我尚停留在石子归并阶段,这题以后是一定要补的…

I.起起落落

题意:给定一个数组 p n p_n pn​,在[1,2,3…n]这个序列中,有多少个持续下降的子序列,定义持续下降的子序列 a 1 . . . a 2 m + 1 a_1...a_{2m+1} a1​...a2m+1​ 为:
1. a 1 &lt; a 2 &lt; . . . &lt; a 2 m + 1 &lt; = n a_1&lt;a_2&lt;...&lt;a_{2m+1}&lt;=n a1​<a2​<...<a2m+1​<=n;
2.对于任意的 k k k,有 p [ a [ 2 k − 1 ] ] &gt; p [ a [ 2 k + 1 ] ] &gt; p [ a [ 2 k ] ] p[a[2k-1]]&gt;p[a[2k+1]]&gt;p[a[2k]] p[a[2k−1]]>p[a[2k+1]]>p[a[2k]] 成立。

思路:这题其实光看题意是不好理解的,如果拿样例来推一推,就会发现我们需要找的子序列满足的,是一个呈破浪形下降的折线。

令 d p [ i ] dp[i] dp[i]为以ai结尾的持续下降子序列的个数,则 d p [ i ] dp[i] dp[i]的值是与ai后面的值无关的,考虑 j ∈ [ 1 , i − 1 ] j∈[1,i-1] j∈[1,i−1],若 a j a_j aj​小于 a i a_i ai​,则 a j a_j aj​可以作为以ai为结尾的持续下降子序列的中间节点;若 a j a_j aj​大于 a i a_i ai​,则代表 a i a_i ai​与其中间结点可以接在以 a j a_j aj​为结尾的中间结点的后面,表达式为:
d p [ i ] + = ( d p [ j ] + 1 ) ∗ k dp[i] += (dp[j]+1)*k dp[i]+=(dp[j]+1)∗k 。 k k k代表符合条件的中间结点个数,加1是因为 a j a_j aj​, k k k, a i a_i ai​,其本身也是一种持续下降子序列的方案。

a i a_i ai​和中间结点直接这样接 a j a_j aj​在后面会满足持续下降子序列的条件吗?满足,因为题目要求的 2 k 2k 2k是一个偶数,我们的子序列每次都是2个2个拼接上去的,一定满足持续下降的条件。

#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
int main()
{int n;scanf("%d",&n);int p[n+1];for(int i = 1;i<=n;i++)scanf("%d",&p[i]);long long dp[n+1];memset(dp,0,sizeof(dp));long long ans = 0;for(int i = 3;i<=n;i++){int k = 0;for(int j = i-1;j>=1;j--){if(p[j] < p[i])k++;else if(p[j] > p[i])dp[i] += (dp[j]+1)*k%mod;}ans = (ans + dp[i])%mod;}cout<<ans<<endl;return 0;
}

J.夺宝奇兵

题意:n个人手上持有m个宝物,第i个宝物的价格为 a i a_i ai​,问需最少要准备多少金币将宝物买过来使自己能成为拥有宝物最多的人。

思路:一个看上去比较暴力的做法,枚举每个居民手中剩下0个宝物,1个宝物,m/2个宝物,如果自己拥有的宝物不是最多的,再将一些没买的宝物买过来,比较这多种方案,取最小花费。

这题是cf的原题,队友现场做的,但因为数据有很大的问题,队友怎么敲都没过,数据修正后一发A的。赛后请教队友补的这道题,真的是一种很巧妙的思想,学习到了。

K.星球大战
暂未解决。

2019 CCPC-Wannafly Winter Camp Day1 (Div2, onsite)(补题记录)相关推荐

  1. 2019 CCPC-Wannafly Winter Camp Day8 (Div2, onsite) 补题记录

    一篇来自ACM入门者的补题记录 最近有点懒,想着还有最后一篇博客没完成,是我最大的补题动力. 不过终于在camp过去三个月的时候完成了所有的补题博客,有点欣慰,下一个目标应该是补一补一年前暑期训练的题 ...

  2. CCPC-Wannafly Winter Camp Day8 (Div2, onsite) 补题

    A Aqours 题解: https://www.cnblogs.com/qieqiemin/p/11251645.html D:吉良吉影的奇妙计划 (暴力打表) 题目描述 吉良吉影是一个平凡的上班族 ...

  3. CCPC-Wannafly Winter Camp Day1 (Div2, onsite) J 夺宝奇兵 暴力 贪心

    J-夺宝奇兵 思路:看着题比较晚了,一看woc这不就是CF原题嘛,考虑枚举最终票数.枚举完票数就开始处理,把每个党超过这个票数且收钱最少的人收买过来,如果这些人都收买完了可是还没有达到预定的票数,就一 ...

  4. CCPC-Wannafly Winter Camp Day8 (Div2, onsite) A 题 Aqours (精巧的树形DP)

    题目链接: https://www.cometoj.com/contest/29/problem/A?problem_id=414 Aqours 题目描述 Aqours 正在 LoveLive! 决赛 ...

  5. 阔力梯的树(2020 CCPC Wannafly Winter Camp Day2 Div.12 )dsu on tree

    题解: dsu on tree dsu on tree的基本步骤就不说了 看到这题询问结点的子树问题,而且询问时离线的,首先想到的dsu on tree的这个trick. 本题的难题就是如何维护结点所 ...

  6. 2019 CCPC wannfly winter camp Day 5

    C - Division 思路:我们考虑到一点,从大往小取得顺序是不会有问题的,所以可以直接主席树,但是开不下空间,我们可以log分段求. #include<bits/stdc++.h> ...

  7. CCPC-Wannafly Winter Camp Day3 (Div2, onsite) I 石头剪刀布(按秩合并并查集)

    题解:每次有两个事件: y y去挑战xx,如果赢了可以坐在x x的位置,打平或者输了就要被淘汰. 询问在进行所有一类事件后,有多少种情况可以让x x现在还没有被淘汰. 对于第二类事件,我们假设x x挑 ...

  8. 2019 CCPC wannfly winter camp Day 8

    E - Souls-like Game 直接线段树合并矩阵会被卡T掉,因为修改的复杂度比询问的复杂度多一个log,所以我们考虑优化修改. 修改的瓶颈在于打lazy的时候, 所以我们预处理出每个修改矩阵 ...

  9. CCPC-Wannafly Winter Camp Day8 (Div2, onsite)

    Replay Dup4: 厕所是个换换脑子的好地方? 要读题啊,不要别人不做,自己就跟着不做啊 X: 读题很重要啊!什么时候才能读对题 不演队友啊 D题看错题, 直到最后一小时才看懂 很多时候要看榜单 ...

最新文章

  1. 05-RARP: 逆地址解析协议
  2. Framework中网络定位服务简介
  3. 【资讯】K8S生态再添一员,Rancher发布开源HCI软件Harvester、及其安装教程
  4. boost::next_permutation相关的测试程序
  5. # 普通函数和箭头函数的区别
  6. vue 实现 web端滚动刷新 排序 筛选 响应式布局 (源码)
  7. 带有示例的Python File readlines()方法
  8. CEF编译 执行gn args out\Release_GN_x86异常
  9. android中requestFocus 以及与setFocusable的区别
  10. WordPress文章ajax,使用ajax在WordPress后台删除文章方法
  11. intel CPU详解
  12. 【汉字识别】基于matlab SVM汉字识别【含Matlab源码 830期】
  13. 《Multiplayer Game Programming》阅读笔记
  14. 如何快速爬取一个网站所有图片链接
  15. linux中安装mysql无法启动不了_Linux中安装mysql之后 mysql服务不能启动是怎么回事?...
  16. mysql upsert语法_Mysql - Upsert功能实现
  17. arcgis desktop和arcgis engin连接postgresql数据库连接需要的类库
  18. 如何固定Excel的表头和列(滚动时始终显示表头和首列)
  19. 浅析SCI论文发表和转让
  20. 随机分布嵌入使短时高维序列可预测

热门文章

  1. [转载] 测试一个杯子
  2. html5的a能不能放div,从a标签为什么不能包含div标签-了解HTML5元素分类与内容模型...
  3. 【华为OD机试 2023最新 】 机房布局(C++ 100%)
  4. 怎么解决高并发下抢红包和商品超卖问题?
  5. 项目实战——基于计算机视觉的物体位姿定位及机械臂抓取(单目标定)
  6. win7访问win10共享打印机
  7. 人工智能的国家级发展战略目标(摘自《国务院关于印发新一代人工智能发展规划的通知》)2017年7月
  8. SQLZOO_Window LAG
  9. MATLAB画图颜色渐变
  10. 【SDK 教程】 让 3D 模型 “活起来” 的好方法在这里!