08 2012 档案
摘要:模型:给一个完全二部图,每条边都有一个权值,求边权和最大的匹配。数据范围:n<=250分析:直接套用KM算法即可,要加slack数组优化,优化后复杂度为O(N3)。View Code #include <stdio.h>#include <string.h>#define N 300#define INF 0x7fffffff#define MIN(a,b) ((a)<(b)?(a):(b))#define MAX(a,b) ((a)>(b)?(a):(b))int n,g[N][N];int x[N],y[N],lx[N],ly[N],match[N
阅读全文
摘要:题意:给一棵树,当在某个结点上放置士兵时,与该点相邻的边就被看守住了,求最少需多少士兵才能看住树中所有边。分析:先将无根树有根化,然后DP。状态设计: 1、dp[i][0],表示在结点 i 没放置士兵的情况下,看住以结点 i 为根的子树的所有边所需的最少士兵; 2、dp[i][1],表示在结点 i 放置士兵的情况下,看住以结点 i 为根的子树的所有边所需的最少士兵。状态转移: 1、dp[i][0]=∑dp[j][1],j 是 i 的儿子结点;(根结点不放士兵时,与其相连的边必须由儿子结点来看守) 2、dp[i][1]=1+∑ ( MIN ( dp[j][...
阅读全文
摘要:题意:给出N个词根,求长不超过L的且至少包含一个上述词根的单词的个数。数据范围:0<N<6,0<L<2^31这题与上一题差不多,但比上题要繁琐的多,关键的区别在于"不超过L" 和"至少包含一个"因为"至少包含一个",所以刚好是求上一题的反面;因为"不超过L",所以要求的是矩阵幂和S = A + A2 + A3 + … + AkView Code #include <stdio.h>#include <string.h>#include <queue>#in
阅读全文
摘要:题意:给出m个致病DNA片段,求长为n且不含致病片段的DNA序列共有多少种。数据范围:0 <= m <= 10,1 <= n <=2000000000这题初看起来与上一题差不多,但一看数据范围就傻了……分析:先建m个致病DNA片段的自动机,然后求出自动机中结点之间转移的路径数目,这样就可以得到一个有向图,所求问题就变为从根结点出发,到达任意一点,所走路径长度为n且路径不经过危险结点的路径数目。再抽象一下,就是求一个边长均为1的有向图中2点之间长为n的路径数目,这就不难想到矩阵了。设G为邻接矩阵,则Gk中第i行j列的元素表示从i到j长为k的路径数目。View Code #
阅读全文
摘要:题意:给出包含n个可见字符的字符集,以下所提字符串均由该字符集中的字符构成。给出p个长度不超过10的字符串,求长为m且不包含上述p个字符串的字符串有多少个。数据范围:1<=n,m<=50,0<=p<=10状态设计:dp[i][j],i 步之内未经过危险结点且第 i 步到达结点 j 的路径数目。状态转移:dp[i][j]=∑dp[i-1][k],在结点 k 加输入 s[i] 能跳到结点 j初始化:dp[0][0]=1,对于其余的 i :dp[0][i]=0注意:由于最后结果很大,而题中又没提到取模,所以要用到大数相加。View Code #include <stdi
阅读全文
摘要:题意:先给出m个DNA片段(含致病基因),然后给一个长为n的DNA序列,求最少需要修改多少次,使得这个DNA序列不含致病基因。修改操作定义为将DNA中某个碱基变为另一个碱基,如将A变为G数据范围:1<=m<=50,1<=n<=1000分析:先建自动机,然后DP。状态设计:dp[i][j]为从根结点出发走 i 步后到达状态 j 最少需要修改的次数。状态转移:1、dp[i][j]=MIN(dp[i-1][k]),从状态k能根据s[i]跳到状态j,无需修改;2、dp[i][j]=MIN(dp[i-1][k])+1,从状态k不能根据s[i]跳到状态j,需要修改s[i]。(注意区
阅读全文
摘要:题意:给出2个深搜过程,确定是否是对同一棵树的遍历。深搜过程是用01串来描述的,0代表远离树根,1代表靠近树根。分析:利用最小表示的思想,我们将树的所有结点按一定的规则排个序,然后比较2棵树的结点是否一样即可。排序规则:先按深度排序(离树根的距离),深度相同的按以该结点为根的子树结点数目排序。其实排序的过程就是统一遍历规则的过程,利用上面的规则排序后的结点是一个宽度优先的搜索顺序,且同一层中按后代结点数目小的先遍历。View Code #include <stdio.h>#include <stdlib.h>#include <string.h>#defin
阅读全文
摘要:题意:Given a n × n matrix A and a positive integer k, find the sum S = A + A2 + A3 + … + Ak.分析:与矩阵快速幂的思想一样,都是二分。1、k为偶数,设k=2*m,则S = A + A2 + A3 + … + Am+(A + A2 + A3 + … + Am)*Am2、k为奇数,设k=2*m+1,则S = A + A2 + A3 + … + Am+(A + A2 + A3 + … + Am)*Am+Ak由上可见,原问题均可递归成与原问题结构相同的子问题,递归边界为k=1时,结果为AView Code
阅读全文
摘要:题意:给n个矩形,每个矩形都有一个矩形的“洞”,矩形和洞的边都与坐标轴平行,求这些带“洞”的矩形覆盖的面积。数据范围:n<=50000, 0<=x,y<=50000分析:这题本质还是求矩形面积并,因为一个带“洞”的矩形可以看成是4个矩形。由于矩形数目n和坐标范围均比较大,所以离散化+暴力统计的方法肯定会超时。扫描线的方法我也是第一次学,我的理解是这样的,把所有矩形的2条竖直边(横边也一样)无限延伸就得到扫描线,这些线把所有矩形重新划分为许多不相交的矩形,所有矩形的面积并其实就是夹在这些线之间的矩形的面积之和,夹缝中的矩形的宽就是扫描线之间的距离,关键在于夹缝中矩形的高度是多少
阅读全文
摘要:题意:在二维平面上给出n个矩形的顶点坐标(浮点数),每个矩形的边都平行坐标轴,求矩形覆盖的面积。数据范围:n<=100, 0=<x,y<=100000分析:由于n比较小,所以用离散化就能过(离散化的具体分析见上一篇)。View Code #include <stdio.h>#include <string.h>#include <stdlib.h>#define N 110int n;double xl[N],yl[N];double xr[N],yu[N];double x[2*N],y[2*N];int xcnt,ycnt;bool f
阅读全文
摘要:题意:在二维平面上给出n个矩形的坐标,矩形的边与x轴和y轴平行,求这n个矩形覆盖的面积。数据范围:n<=1000, x,y均为不大于50000的正整数分析:由于坐标都是整数的,我们可以把二维平面看成由面积都是1的小方格组成,最暴力的方法就是标记每个矩形覆盖的小方格,最后再统计一共有多少小方格被覆盖,但是坐标平面太大了,最坏情况下为50000*50000,肯定超时了。虽然坐标范围比较大,但是矩形个数却比较小,此时不难想到离散化,离散化后,我们不再将坐标平面划分为面积为1的小方格,而是根据在n个矩形中出现过的坐标来划分,这样的话,最后划分出来出来的方格数目不会超过2n*2n,这样就不会超时了
阅读全文
摘要:模型:给一个n个点的无向带权图,求从指定起点出发,经过指定的k个点(顺序不定)最后回到起点的最小代价。数据范围:n<=10^4, m<=10^5, k<15分析:先求最短路,求出从指定的k+1(含起点)个点到其他点的最小代价,然后建立k+1个点之间的最小代价邻接矩阵。最后用状态压缩DP求结果(状态压缩DP参考上一篇)。View Code #include <stdio.h>#include <string.h>#include <queue>using namespace std;#define MIN(a,b) ((a)<(b)?(
阅读全文
摘要:模型:求n个城市的最短hamilton回路,n<=15。分析:看到n<=15这样的条件容易想到状态压缩DP。hamilton回路其实就是n个城市的一个圆排列,任选一个起点最后的结果都一样,我们不妨设结点0为起点,状态设计也就不难了。状态设计:d[s][last],表示从结点0出发,已经走过的结点构成状态s,最后走的结点为last;状态转移:d[s][last]=MIN(d[ns][k]+g[k][last]),ns为s中去掉last那一位,k为ns中是1的位(不能是起点0);边界:当s中只有2位是1的时候,说明从0结点出发,到达last,所以直接返回g[0][last]。结果:an
阅读全文
摘要:题意:给一个正整数序列,记为a1,a2,……an,现需找i,j,使得i<j,并且ai与aj之间的数均比ai大,均比aj小,求符合上述条件的i与j,使得j-i的最大。分析:易知序列中的最小值比其他所有数都小,最大值比其他所有数都大,所以可以现找到最小的数与最大的数的位置,记为i,j,若i<j,则区间[i,j]内符合上述条件的最值就是j-i,然后递归求解左右区间[1,i-1],[j+1,n],若i>j,则将区间分为三段递归求解,[1,j],[j+1,i-1],[i,n]。递归边界为区间左端点>=区间右端点时返回-1。每次求区间的最大与最小值的位置可以用线段树解决。View
阅读全文
摘要:题意:给一棵含n个结点的树,现要查询从a到b的路径中是否包含c,共q次查询。1=<n,q<=100000分析:由于在树中从一个结点走到另一个结点的路径是唯一的,其实说的这条路径就是最短路径,然后问题转化为判断一个点是否为在一条最短路径上,此时就不难想到这个这个判断条件d(a,c)+d(c,b)=d(a,b),问题就转化为查询树中2个结点之间的距离,这个可以用LCA来做(参考上一篇),考虑到n和q都比较大,所以用离线LCA.View Code #include <stdio.h>#include <string.h>#define N 100010#defin
阅读全文
摘要:题意:给一棵带权重的树,共有k个查询,每次查询树中2个结点的距离。结点数n最大为40000,k最大10000分析:首先我们将无根树转为有根树,可以在O(n)时间内得到每个结点到根结点的距离。由于在树中从一个结点走到另一个结点的路径是唯一的,所以a到b的路径一定经过lca(a,b),设lca(a,b)=c。此时不难发现d(a,b)=d(a,root)+d(b,root)-2*d(c,root)。先在问题就是如何快速求LCA,由于结点数目比较大,查询比较多,所以用在线算法会超时。这里用的是tarjan离线算法,时间复杂度为O(n+k)。View Code #include <stdio.h&
阅读全文
摘要:模型:给定一个整数矩阵,查询某个子矩阵中的最大数与最小数之差。N最大为250,查询数K最大为100000我的做法:用线段树求出要查询的子矩阵每一行的最大与最小,然后在列方向上统计子矩阵的最大与最小。有点暴力,跑了800+ms。View Code #include <stdio.h>#include <string.h>#define N 255#define MAX(a,b) ((a)>(b)?(a):(b))#define MIN(a,b) ((a)<(b)?(a):(b))int n,b,k,D;int max[N][4*N];int min[N][4*
阅读全文
摘要:题目大意:给你一个含n个整数的不下降序列,现需查询某个区间内出现次数最多的数,对于每次查询输出出现最多的次数即可。分析:由于序列是有序的,所以一个数如果在序列中出现多次,那么一定是连续出现的,这样的话就可以把问题转化为区间染色问题,查询的是某个区间中最长的同色区间的长度。区间保存的关键信息有,区间内的某数出现的最大次数,区间最左边的数及其在该区间内出现的次数,区间最右边的数及其在该区间内出现的次数。保存左右两边的信息为为了更新父结点,因为父结点的最大answer可能由左儿子和右儿子合并得到。这题我一开始用堆实现的线段树,发现了很多问题,用堆实现的线段树中有很多没有用到的空间,处理不好会造成结果
阅读全文
摘要:定义windy数:相邻数字的差至少是2的数,例如10不是windy数,而13是windy数。求给定区间中有多少windy数。区间端点范围为 [1, 2000000000]dfs写法#include <stdio.h>#include <string.h>#define N 10int dp[N][N],digit[N];int dfs(int pos,int last,int z,int f){ if(pos==-1) return 1; if(z&&!f&&dp[pos][last]!=-1) return dp[pos][last];
阅读全文
摘要:题意:求n到m中有多少个数不含“4”和“62”View Code #include <stdio.h>#include <string.h>#define LEN 10char a[LEN],b[LEN];int n,m;int dp[LEN][3][2];int nextstate(int cur,int in){ if(cur==2 || cur==1&&in==2 || in==4) return 2; return in==6;}int nextflag(int cur,int in,int max){ if(cur==1 &&
阅读全文
摘要:题目大意:求1到n中有多少个数含“49”第一次接触按位DP,参考了别人的题解。第一个代码运行速度快些(31ms),但状态的转移的分析比较麻烦,第二个代码要慢些(125ms),但code比较方便。View Code #include <stdio.h>#include <string.h>#define LEN 22typedef __int64 LL;char s[LEN];LL dp[LEN][3][2];int next(int cur,int in){ if(cur==2 || cur==1&&in==9) return 2; return in=
阅读全文
摘要:题目大意:给一个n*m的方格地图,每个方格中有一个字符,'.'草地,'*'泥巴地,给你一些宽为1方格大小的板子,长度不限,问最少需要多少板子才能盖住所有的泥巴地,但是不能盖住草地,板子允许相互覆盖。分析:扫描行,将连通的泥巴地看成一个结点,这样得到二分图的X部,按同样的方法扫描列得到二分图的Y部,有公共方格的结点之间连边。View Code #include <stdio.h>#include <string.h>#define N 51#define M 51char map[N][M];bool g[N*M][N*M];int n,m
阅读全文

浙公网安备 33010602011771号