![](https://img-blog.csdnimg.cn/20201014180756919.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
牛客
Ray.C.L
不开longlong见祖宗
展开
-
45届ICPC昆明站热身赛C-Statues
题意:有n个位置,k个雕像,第i个雕像初始位置为pi,重量为si。现在你要移动他们的位置,将雕像i从位置x移动到位置y的代价为si*|x-y|,其中si是雕像的重量问将雕像按重量非降序摆放的最小总移动代价是多少。数据范围:k<=n<=5e3,s<=1e6思路:先排出最后的状态,在初始位置不同的情况下吧重量小的放前面,否则吧位置靠前的放前面,然后dp找最小代价。dp[i][j]表示前i个已经放好,并且第i个在j位置的最小代价。那么可得dp[i][j]是由min{dp[i-1]原创 2021-04-08 23:19:05 · 225 阅读 · 0 评论 -
Perfect Security(01字典树)
题目链接题意:给你两个序列A,B,求一个序列C c[i]=a[i]^b[i]你可以重新排列B序列,且要答案字典序最小。思路:对B序列建树,然后在A序列查找,为了找到数尽可能小,那么贪心的时候就是看01树上的点和有没有和当前位一样的有的话就选他,异或后对答案没影响,没有的话就只能加上当前位异或值(1<<i),还要删除字典树的节点,我们用sum[i]记录一想当前节点还有几个子节点可以走,当子节点减为0时则不能走。//#pragma GCC optimize(2)#include<bit原创 2020-11-05 23:06:18 · 232 阅读 · 0 评论 -
NC 112209 Vitya and Strange Lesson(01字典树)
题意:给你n个数的序列m个操作,每次操作给你一个数,然后让序列中所有的数异或这个数最后求当前序列的mex(最小未出现的非负值)思路:异或有结合律那么我们就把后面输入的数异或一下,然在n 个数上的字典树去找没出现的值,我们去记录一下当前树的节点,看他是不是满二叉树,如果是满的那说明在这条路径上没有未出现的数,我们就跳到另一边,然后此时当前位只能为1所以加上1<<i//#pragma GCC optimize(2)#include<bits/stdc++.h> using n.原创 2020-11-04 21:31:01 · 207 阅读 · 0 评论 -
奶牛异或(01字典树)
思路:区间异或的值用前缀和的思想,x^ x2…^xn是1——n的异或值 x…x2n是1——2n的异或值或者这两个数异或一下就是n——2n的异或值,那么求奶牛区间异或值最大,我们就可以吧前缀异或值建树,从中找2个异或值最大的就是要的答案,为了保证最短并且等级最高,我们从前往后每次进来一个数先求树中最大的异或值然后再把他加进去。为了记录位置,我们再sum[root]里面记录数的位置。//#pragma GCC optimize(2)#include<bits/stdc++.h> using.原创 2020-10-28 20:57:10 · 205 阅读 · 0 评论 -
起床困难综合征(按位贪心)
思路:从0-M中选出一个数使得其求多个位运算后的最大值,位运算当时是按位去算,那么我们要使得最后答案尽可能就从高位向低位枚举看这个位能不能填1,我们首先假设从M中选的是每一位全0和每一位全1,经过几次位运算后,得到最后的答案,通过这个答案我们就可以观察出最后的答案ans的每一位到底是选1还是0,如果此时选0或者1都可以那么选0,(优选选全0状态下此位为1的),如果不行的话,我们看看当m中选出的这个数的这一位是1的时候能不能使答案的这一位是1。#pragma GCC optimize(2)#includ.原创 2020-10-25 10:35:39 · 252 阅读 · 0 评论 -
环形石子合并(区间dp)
思路:和普通石子合并不同的是可以首位合并那么我们吧数组开2倍后面n+1到2n存储1到n相同的东西,dp[l][r]表示从L-R区间的最大值,每次石子都是有之前的2堆合并的,所以枚举中间点即可,dp[l][r]=max(dp[l][r],dp[l][k]+dp[k+1][r]+val[l][r]),其中val是合并L-R区间所需的代价我们用前缀和即可算出。#pragma GCC optimize(2)#include <cstdio>#include <cstring>#in.原创 2020-09-26 19:44:27 · 184 阅读 · 0 评论 -
郊区春游(状压dp,TSP问题)
思路:我们选几个点走,就用二进制枚举所有可能的情况1表示走过0表示没有走过,我们用dp[st][i]表示当前状态为st且最后到的点i的最短距离,那么可以发现他的当前状态st是由st‘来的st’必定比st少一个1,那么所以符合条件的dp[st][i]=dp[st’][j]+dis[j][i]转移过来,dis是j到i的最短距离,通过弗洛伊德算法求出来即可,然后在找出符合条件的状态进行转移。当st’i位置比st少个1时那么他转移的状态就是st’+(1<<(i-1))==st(目标状态)#pragm.原创 2020-09-26 14:12:13 · 201 阅读 · 0 评论 -
小琛和他的学校(树形dp)
思路:计算每条边走了几次,用num[i]表示以i为根的节点个数有多少,sum[i]表示以i为根的人数总和是多少我们看这个图 (丑) 要算1和2节点之间的边走过几次就是用sum[2]*(n-num[2])+(allpeople-sum[2])*num[2],意思是这条边左边的所有人要前往右边所有点的次数+右边的所有人前往左边所有点的次数。因为要走2遍所以乘个2就行#include<bits/stdc++.h>typedef long long ll;using namespace st.原创 2020-09-18 20:57:51 · 145 阅读 · 0 评论 -
道路和航线(SPFA优化,拓扑排序+迪杰斯特拉)
思路:SPFA的优化#include<bits/stdc++.h>using namespace std;typedef long long ll;const int N=200005;const int mod=1e9+7;const int M=(1<<10)+5;const int inf=0x3f3f3f3f;int n,T,R,S;struct node{ int to,nex,w;}edge[N];int head[N],tot,dis..原创 2020-09-14 20:17:29 · 176 阅读 · 0 评论 -
乐团派对(dp)
思路:dp[i]表示前i 个乐手可以组成乐团的最大值,为了方便处理所以我们要先排序,我们可以发现如果i-a[i]>=0那么有2种选择一种是在i-a[i]+1处新建一队,或者是直接加入前i-1个人组成的队伍,dp[i]=max(dp[i-1],dp[i-a[i]]+1),如果i-a[i]<0那么说明第i个人必定落单,不能构成乐队此时dp[i]=0#include<bits/stdc++.h>using namespace std;const int N=1e5+5;int d.原创 2020-08-30 12:39:13 · 145 阅读 · 0 评论 -
逃跑路线
思路:我们可以发现&(2^1-1) & … (2^n)=1那么题目就转换成判断是奇数还是偶数那么我们只需要判断最后一位&是0还是1即可#pragma GCC optimize(2)#include <cstdio>#include <cstring>#include <algorithm>#include <set>#include<iostream>#include<vector>#inclu.原创 2020-08-29 18:44:51 · 301 阅读 · 0 评论 -
使徒来袭(二分)
思路:已知3个数的积,求3个数和的最小值,那么当3个数相等时和是最小的,二分答案即可。#pragma GCC optimize(2)#include <cstdio>#include <cstring>#include <algorithm>#include <set>#include<iostream>#include<vector>#include<queue>#include<map>.原创 2020-08-29 10:08:40 · 358 阅读 · 0 评论 -
选课(树形dp)
思路:建立一个超级源点0,让内些不用学习前置课程的点作为0的子节点,用dp[i][j]表示以i为根节点选了j门课程的最大值,枚举以i为根节点,v为子节点的各种课程的分配办法,可得dp[i][j]=max(dp[i][j],dp[i][j-k]+dp[v][k]),如果i不是源点,那么每次点亮一个新技能都需要点亮自己这一个,那么dp[i][j]=dp[i][j-1]+val[i]#include <cstdio>#include <cstring>#include <a..原创 2020-08-18 16:33:17 · 353 阅读 · 0 评论 -
黑白树(树形dp)
思路:从子节点染色然到父节点,我们看每个节点的覆盖长度还有他子节点的覆盖长度,如果他的覆盖长度dep[u]>dp[v]-1他子节点的覆盖长度那么我们就去用大的更新dep[u]=max(dep[u],dep[v]-1)然后我们记录一下当覆盖距离为0时,他就只能靠自己去覆盖#include <cstdio>#include <cstring>#include <algorithm>#include <set>#include<iostre..原创 2020-08-17 17:11:55 · 613 阅读 · 0 评论 -
旅游(树形dp最大独立集)
思路:问能住几个晚上,每个晚上住的地方都是不相邻的,最大独立集问题。dp[i][0/1]表示以i为根节点并且不选/选这个点的最大值。如题i节点如果选了那么下个节点必定不能选dp[i][1]+=dp[v][0]dp[i][1]+=dp[v][0]dp[i][1]+=dp[v][0]如果i不选那么子节点可选可不选dp[i][0]+=min(dp[v][1],dp[v][0])dp[i][0]+=min(dp[v][1],dp[v][0])dp[i][0]+=min(dp[v][1],dp[v][0])#i..原创 2020-08-17 12:49:53 · 157 阅读 · 0 评论 -
吉吉国王(树形dp)
思路:题目要求的是减去所有叶子结点的值不超过m时,最长边的最小值是多少?dp[i][j] 表示j为最长的边,以i为根节点,减去所有叶子节点的最小总权值。那么我们有2种选择1.减去子节点中与叶子节点相连的边,dp[i][j]+=dp[v][j](1<j<(v的权值)dp[i][j]+= dp[v][j](1<j<(v的权值)dp[i][j]+=dp[v][j](1<j<(v的权值)这里我们判断一下v是不是叶节点如果是叶节点那么权值为inf。2.减掉与子节点相连的边..原创 2020-08-12 18:20:44 · 377 阅读 · 0 评论 -
素数回文 (Miller-Rabin素数测试算法)
朴素算法能过#include <cstdio>#include <cstring>#include <algorithm>#include <set>#include<iostream>#include<vector>#include<queue>#include<stack>#include<bits/stdc++.h>using namespace std;typedef .原创 2020-08-11 23:05:41 · 312 阅读 · 1 评论 -
树上子链(树形dp)
思路:dp[i]表示以i为根节点的子链最大值是多少,i为根时,v为i的子节点,我们可以让i和v两条链相连可得,res=max(res,dp[u]+dp[v]),在dfs的时候不断合并两条链取最大值,然后我们再更新此时的u链看需不需要替换掉上次的内条链,dp[u]=max(dp[u],a[u]+dp[v]),因为可能全为负数所以我们每次最开始取一次啊最大值。#include <cstdio>#include <cstring>#include <algorithm>..原创 2020-08-11 18:46:35 · 615 阅读 · 0 评论 -
二叉苹果树(树形dp)
思路:题中说明这是标准的二叉树,给我们q个枝那说明连了q+1的点,我们就可以吧边的权值用节点去存,用dp[i][j]表示以i为根节点,连了共j个节点的最大值,因为每个节点只有2个或0个子节点,那么我们枚举2个子节点可能连接的节点数,我们先dfs一次去求出每个节点的2个子节点分别是谁,并在此时给节点附上对应的权值转移方程dp[u][i]=max(dp[L][k],dp[R][i-k-1])+dp[u][1] (0<k<i)表示左儿子取k个节点,那么右儿子就取i-k-1个节点(因为还有父亲节点所..原创 2020-08-11 16:00:56 · 582 阅读 · 0 评论 -
Cell Phone Network(树形DP,最小支配集)
思路:要选最少的点去覆盖完整个树,根据覆盖关系我们有3个状态。1.dp[i][0]表示以i为根节点,选i覆盖完所有子树的最小值2.dp[i][1]表示不选i,i节点被子节点覆盖3.dp[i][2]表示不选i节点,i节点被父亲节点覆盖。对于第一种状态,i选以后他的子节点的覆盖关系就是3种取最小dp[i][0]=1+∑min(dp[v][0],dp[v][1],dp[v][2])dp[i][0]=1+\sum min(dp[v][0],dp[v][1],dp[v][2])dp[i][0]=1+∑min.原创 2020-08-10 23:00:29 · 444 阅读 · 0 评论 -
排座椅(贪心)
思路:行和列怎么划分相互没有干扰,分开算,根据给的坐标我们去算那个位置接耳的人多我们去吧他们分开,存一下位置,最后答案要对位置从小到大输出。#include <cstdio>#include <cstring>#include <algorithm>#include <set>#include<iostream>#include<vector>#include<queue>#include<stack.原创 2020-08-10 17:40:39 · 275 阅读 · 0 评论 -
poj1463 NC106060 Strategic game(树形DP,树的最小覆盖点)
题意: 一城堡的所有的道路形成一个n个节点的树,如果在一个节点上放上一个士兵,那么和这个节 点相连的边就会被看守住,问把所有边看守住最少需要放多少士兵。思路:用dp[i][0]表示以i为根节点,但是i节点不放士兵需要看守的最少士兵是多少,dp[i][1]表示以i为根节点,i节点放置守卫时所需的最少士兵,v为u的子节点,当u这个点不选的时候,那么以u延展的边则无人看守此时u的子节点必须有守卫那么dp[u][0]=∑dp[v][1]dp[u][0]=\sum dp[v][1]dp[u][0]=∑dp[v][1原创 2020-08-10 13:47:57 · 152 阅读 · 0 评论 -
小G有一棵大树(树形DP)
思路:找平衡点,删掉一个点后子树节点差最小的就是平衡点,size[i]表示以i节点给根的子节点的个数,f[i]表示删除i节点后最大联通块的节点数,v代表i的子节点,f[i]=max(max(size[v]),n-size[i]),当i节点作为平衡点删去后,留下的最大联通块的节点数要么是他上面的树的节点(n-size[i])要么是子树的最大值size[v],然后在这里面求最小的就是要平衡点,再找一下这些平衡点的编号最小的。#include <cstdio>#include <cstri.原创 2020-08-08 12:47:21 · 334 阅读 · 0 评论 -
双栈排序(二分图判断+思维)
思路:要使用2个栈操作使得序列升序,我们可以发现当2个数a[i] a[j]不能放入同一个栈中的时候,要满足条件 i<j<k && a[k]<a[i]<a[j]这里呢,我们用dp[i]表示从i开始到结尾的最小值,不能放到同一个栈中我们就把他分开,这样我们要求的就是能不能构成2个符合条件的独立集,我们根据这个条件去建图,当a[i] a[j]不能放入同一个栈中,我们将i,j建一条边,然后用染色法判断二分图,不能构成二分图答案就是0,能构成的话,我们先涂的色为1,后涂色为..原创 2020-08-07 17:35:42 · 217 阅读 · 0 评论 -
紫魔法师(dfs染色)
思路:我们可以发现,当出现3个点构成环时需要用的颜色最多是3种,剩下都可以用2个色完成,当只有1个点的时候只需要1种颜色。dfs的时候判断一下是否有3个点构成环#include <cstdio>#include <cstring>#include <algorithm>#include <set>#include<iostream>#include<vector>#include<queue>//#incl.原创 2020-08-07 15:30:28 · 349 阅读 · 0 评论 -
P3143 [USACO16OPEN]Diamond Collector S(DP)
思路:dp1[i]表示前i个钻石最多能一起放多少个,dp2[i]表示从i开始钻石放多少个,先排序,从左往右遍历算dp1,如果a[i]-a[cnt]>k(cnt<=i)那说明cnt不能继续放了要缩短这个区间,dp[i]=max(dp[i-1],i-cnt+1),从后往前遍历一遍算dp2[i],如果a[cnt]-a[i]>k(cnt>=i),说明I——cnt这段不能继续放了需要缩短,dp2[i]=max(dp2[i+1],cnt-i+1),然后遍历一遍 取dp1[i]+dp2[i+1].原创 2020-08-07 11:42:48 · 397 阅读 · 0 评论 -
灰魔法师(暴力)
思路:枚举可能的完全平方数,用个map存储a[i]的出现次数,看每个数对完全平方数的贡献次数#include <cstdio>#include <cstring>#include <algorithm>#include <set>#include<iostream>#include<vector>#include<queue>//#include<bits/stdc++.h>using nam.原创 2020-08-05 19:54:38 · 151 阅读 · 0 评论 -
蓝魔法师(树形DP)
思路:树上求方案,dp[i][j]表示以i的子树里连通块个数为j的方案数(j<=k)这里我们有2个选择,1.删除当前边,此时节点u与他的的子节点v所能构成的方案数就是dp[u][x]乘上dp[v][1——x]dp[u][x]=dp[u][x]∗∑i=1xdp[v][i]dp[u][x]= dp[u][x]*\sum_{i=1}^xdp[v][i]dp[u][x]=dp[u][x]∗∑i=1xdp[v][i]2.不删除当前边,此时节点u与节点v构成i+j(i为u的连通块个数,j为v的连通块个数.原创 2020-08-05 16:44:05 · 264 阅读 · 0 评论 -
DDos(记忆化搜索)
思路:因为数据包可以在任何时间发送,那么最后接收到的数据包的数量就是1-n有多少条路径,dp[i]表示从i到n有多少条路径,dp[n]=1,然后记忆化搜索。#include <cstdio>#include <cstring>#include <algorithm>#include <set>#include<iostream>#include<vector>#include<queue>//#includ.原创 2020-08-05 11:21:44 · 109 阅读 · 0 评论 -
购物(背包DP)
思路:和背包长得像,那么我们就往背包上想,dp[i][j]表示前i天我们买了j个糖果的最小花费,dp[i][j]可由dp[i-1][k]转移得到,那么怎么转移?j的范围要<=min(n,i*m)k就最小从i-1个糖果开始(再小就不符合题意)最大到min(j,min(n,(i-1)m))当第i-1天的k个糖果取到第i天的j个糖果就需要加上此时在第i天买糖果的花费就是+前(j-k)个糖果的价格(我们用前缀和去维护),再加上(j-k)的平方。得到dp方程为dp[i][j]=min(dp[i][j],dp[.原创 2020-08-04 18:50:41 · 162 阅读 · 0 评论 -
旅行(最短路暴力)
思路:找经过三个点的最短路最长,我们枚举每一个中转点,以这个中转点为起点跑最短路,在从大到小排序找到2个路径,不断更新。#include <cstdio>#include <cstring>#include <algorithm>#include <set>#include<iostream>#include<vector>#include<queue>//#include<bits/stdc++...原创 2020-08-04 14:21:55 · 142 阅读 · 1 评论 -
合唱队形(LIS)
思路:从题意我们可以发现求一个金字塔形的序列,那么我们就从左往右 ,从右往左求2次最长上升子序列,再遍历一遍可求出最长的金字塔形序列。#include <cstdio>#include <cstring>#include <algorithm>#include <set>#include<iostream>#include<vector>#include<queue>//#include<bits/s.原创 2020-08-03 20:29:18 · 255 阅读 · 0 评论 -
过河(DP+离散化)
思路:dp[i]表示从跳到点i所需的最小次数。dp[i]=min(dp[i],dp[i-j]+vis[i-j]),vis[i-j]表示i-j这个位置有没有石头。因为len是1e9肯定会爆,所以要离散化,每个石头的位置和终点位置,当2个石头相距大于t的时候,那么那么任意的距离都可以表示为d%t+t#include <cstdio>#include <cstring>#include <algorithm>#include <set>#include&.原创 2020-08-03 17:00:37 · 241 阅读 · 0 评论 -
采药(01背包)
思路:dp[i][j]表示从前i个药材中用时j所采药的最大值。那么当j>=w[i]的时候得到转移方程dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i])#include <cstdio>#include <cstring>#include <algorithm>#include <set>#include<iostream>#include<vector>#include<.原创 2020-08-03 11:57:17 · 191 阅读 · 0 评论 -
小A的最短路(LCA)
思路::在树上找2点的最短距离,很容易想到LCA,那么我们在树上找a,b的最短距离,因为缆车的存在所以有3种找法,一种是直接从a节点到b,第二种是a先到缆车x加上b到缆车y的距离,第三种就是a到缆车y加上b到缆车x的距离,我们取个最小值(用C++11会TLE )#include <cstdio>#include <cstring>#include <algorithm>#include <set>#include<iostream>..原创 2020-07-31 22:42:14 · 194 阅读 · 0 评论 -
兔子的区间密码(位运算)
思路:异或值最大,我们就让每一位不同的尽可能多,那么给你区间l,r我们将l,r变成成2进制高位补齐,为了不超过L-R区间从高位向低位遍历时,遇到相同的我们就继续走,如果遇到某一位不同(此时必定是R=1,L=0)那说明从这一位开始后面的每一位0,1我们可以任选,使得从当前位置到后面的每一位异或后变成1,此时值最大#include <cstdio>#include <cstring>#include <algorithm>#include <set>..原创 2020-07-31 13:26:56 · 596 阅读 · 0 评论 -
Xor path(求节点经过次数,异或性质)
思路:当一个数的异或次数为偶数时那么他没有贡献度,所以我们只需要看没个点被走了几次如果是奇数次那么他有贡献度,问题就变成如何求点被走了几次,我们用个数组表示一个个点的儿子个数是多少,假设v是u的儿子,通过dfs遍历u的整个子树,得到儿子的个数,那么从u-》v,u的次数就是p[v] * (n-p[v]),因为遍历时会重复计算一遍要除2,这时我们再看u的父亲fa->u有多少次,就是p[u] * (n-p[u])也要除2,这样就算出了u到被走了几次。#include <cstdio>#in.原创 2020-07-31 11:58:06 · 226 阅读 · 0 评论 -
素数判断(试除法求质因数)
思路:试除法求素数#include <cstdio>#include <cstring>#include <algorithm>#include <set>#include<iostream>#include<vector>#include<queue>//#include<bits/stdc++.h>using namespace std;typedef long long ll;#de.原创 2020-07-25 14:56:55 · 337 阅读 · 0 评论 -
区区区间间间(思维+单调栈)
思路:根据解释,题意就是求每个长度大于1的区间最大值-最小值之和,那么我们用单调栈,l[i]表示以a[i]为最大值最多向左扩展多长,r[i]表示以a[i]为最大值最多向右扩展多长,那么a[i]的贡献就是2种,1.ans+=(r[i]-l[i]+1)a[i]当i处于端点时的贡献.2.ans+=(r[i]-i)(i-l[i])*a[i] i处于中间时的贡献,然后我们吧a[i]=-a[i]就是求最小值的贡献。#include <cstdio>#include <cstring>#..原创 2020-07-19 17:14:43 · 232 阅读 · 0 评论 -
签到题(线段树)
题意:给你三个操作1.添加区间x-y,2.删除区间x-y,3查询总区间长度为多少,我们用线段树去维护区间的长度,用lazy标记标记区间的覆盖次数,如果此时区间已经覆盖了那么长度就是r-l+1,不然就是线段树的左右子树的长度和,如何是点的话就是0#include <cstdio>#include <cstring>#include <algorithm>#include <set>#include<iostream>#include&..原创 2020-07-19 12:53:02 · 159 阅读 · 0 评论