随笔分类 -  HDOJ

摘要:求至少经过K条边,到达终点的最短路(K<=50)。 K比较小,先用Bellman求出走50步到达每个点的最短路,然后把50步的可达点加到队列里SPFA即可。 题解是直接二维最短路的,不过好像比bellman+spfa慢。。目前排在HDOJ第一。。 1 #include <string.h> 2 #include <stdio.h> 3 #include <queue> 4 #define MAXN 5005 5 #define MAXE 200005 6 #define INF 0x3f3f3f3f 7 struct edge{ 8 int u,v,n 阅读全文
posted @ 2012-09-25 14:13 Burn_E 阅读(228) 评论(0) 推荐(0)
摘要:用若干个-1到2的数组成一个最接近D的数(-1<D<2)。过程中不能超过2。 吐槽一下题目,看了半天才看明白。。。。排个序然后背包。。 1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 #define MAXN 205 5 int cas,n,tot,x[MAXN],d[240005]; 6 double x1; 7 int main(){ 8 //freopen("test.in","r",stdin); 9 scanf 阅读全文
posted @ 2012-09-25 14:04 Burn_E 阅读(219) 评论(0) 推荐(0)
摘要:求最小的尾数为X的平方数。 符合情况的数不会有太多,从后向前搜就可以了。 1 #include <string.h> 2 #include <stdio.h> 3 #include <algorithm> 4 #define INF 0x3fffffff 5 typedef long long LL; 6 int cas,n,num[15],len,ans; 7 LL sqr(int x){ 8 return (LL)x*x; 9 }10 void dfs(int l,int mul,int pre){11 if(l==len){12 ans=st... 阅读全文
posted @ 2012-09-23 11:47 Burn_E 阅读(161) 评论(0) 推荐(0)
摘要:题解写了N多方法,我用的是最水的那种。。 起始区间只有(0 <= Fi <= 500),500秒之后排名必然不会变化了。。所以,暴力500秒,然后排个序就行了。 1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 #define MAXN 50010 5 struct stt{ 6 int s,t,v,id; 7 bool operator <(const stt& st)const{ 8 return t>st.t||(t==st.t& 阅读全文
posted @ 2012-09-23 11:45 Burn_E 阅读(149) 评论(0) 推荐(0)
摘要:求比N小的因数最多的数,因数相同时取较小的的。(N<=10^80) 没想法的题目,没想到是搜索。。 首先因子数目 f[i] = ∏(p[i]+1) ,p[i]是所有质因数的个数,这个应该都知道。如果要使因子最多并且数最小,不会用到太大的质数,这个我也不知道怎么证明。。原题解也没有证明。。。 用一个四元组[K,F,N,A[]]表示数K有F个因数,包含N个质因数,每个质因数P[i]分别有A[i]个。然后搜索就可以了,添加一个已有质数A[i],四元组转化为[K*P[i],F/(A[i]+1)*(A[i]+2),N,A[i]+1],添加一个新的质数A[i],四元组转化为,[K*P[i],F*.. 阅读全文
posted @ 2012-09-23 11:33 Burn_E 阅读(380) 评论(0) 推荐(0)
摘要:给出一个区间以及两种区间操作,[1 l,r,c]把l~r的点染成c色,[2,l,r,c]查询l~r内颜色为c的点的数目。 因为c的数目太大,用线段树是存不下的,所以只能另辟蹊径了。虽然网上有线段树的方法,但那个Max-Min剪枝完全是没有作用的,随便出一组数据,把所有点间隔染成3,5,然后查4,这样用线段树不知道要跑多久。。。 题解说这题是裸的分块HASH。。还没写过,学习了。其实就是将原区间划分乘sqrt(n)个区间,每次暴力查询和跟新两边的区间,中间的区间直接用hash存每种颜色的节点的数量。这里用到了类似线段树的lazy思想,区间成段修改直接打个标记,等到要划分这个区间的时候先把... 阅读全文
posted @ 2012-09-23 11:11 Burn_E 阅读(461) 评论(0) 推荐(0)
摘要:求把一个数拆成N个非1的数相乘的方案数有多少种(顺序不一样的算不一样的)。 如果不考虑是否为1的方案数,对原数所有的质因数直接用插板法然后乘起来就可以了,麻烦的是有一个所有数都不能为1的问题,这里可以用容斥原理组成。用f(i)表示有i~N个1的方案数,用x[i]表示确切有i个0的方案数。我们可以得到如下方程组:f(0)=1x[0]+1x[1]+1x[2]+1x[3]+....;f(1)= 1x[1]+2x[2]+3x[3]+....;f(2)= 1x[1]+3x[3]+...;f(3)= 1x[3]+...; 比如在算f(1)的时候,假设有3位数,我们枚举每一位为1,会产生重复的情况... 阅读全文
posted @ 2012-09-23 10:57 Burn_E 阅读(326) 评论(0) 推荐(0)
摘要:给一个有向图,每个顶点的出度为1,A和B是图中的两个顶点,A和B每次只能走一步或者不走,设他们相遇时A走了X步,B走了Y步,使max(x,y)最大,有多解时,使min(x,y)最小,如果还有多解,使x>=y。 其实这个图最特殊的地方就是它每个顶点的出度仅为1。我们都知道树的特性是除了根节点外每个顶点的入度为1,那我们把这个图全部建反向边,也就是说每个顶点的入度为1。但是这个图是有环的,它没有入度为0的根,如果我们把环缩成一个点的话,就会发现这个环的整体入度为0,因为每个点在构环的时候入度就已经饱和了,同样,我们也很容易证明每个连通块至多只有一个环,因为一个连通块不可能有两个入度为0的点, 阅读全文
posted @ 2012-09-20 10:13 Burn_E 阅读(876) 评论(0) 推荐(0)
摘要:按S+W排序即可。 1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 #define MAXN 100005 5 typedef long long LL; 6 struct ppp{ 7 int s, w; 8 bool operator < (const ppp& p) const { 9 return s + w <= p.s + p.w;10 }11 }p[MAXN];12 int n;13 int main() {14 while (scanf 阅读全文
posted @ 2012-09-20 09:23 Burn_E 阅读(128) 评论(0) 推荐(0)
摘要:求用一个串的四个子串能覆盖原串的最大和最小长度。 比赛的时候没有出这一题,其实思路上差不多都是对的,但细节上没有实现好。。 三维的字符串DP,首先处理出每个子串能够开始的位置,这个暴力一下就行。然后用d[i][j][k]表示长度为i状态为j从当前位置开始已经有k个字符被覆盖的最小长度,j是个四位的二进制状态,为1代表已经使用了这个串。当前位置可以选择使用或者不使用新的未使用子串,DP的时候采用刷表会好写的多。 最小和最大的求法是一样的,开两个数组会爆空间。。改用short就行了。。其实写个函数也挺方便的。。 1 #include <string.h> 2 #include < 阅读全文
posted @ 2012-09-20 09:08 Burn_E 阅读(340) 评论(0) 推荐(0)
摘要:求一个K进制下是N的倍数的数,要求这个数使用的数字最少,数字个数相同时取较小的数。 首先有一个结论,至多用两个数字可以构造任意数的倍数。假设只有一个数字吗,由这一个数字构成的数模N的结果只能是0~N-1,由抽屉原理可知必然存在两个数模N的结果相同,这两个数一减,结果有两个数字构成,模N的结果是0。 然后就暴力BFS吧,队列中存的是余数,找到余数为0或者出现已经出现过的余数就返回。每次找到解比较跟新一下即可。 1 #include <string.h> 2 #include <stdio.h> 3 #define MAXN 10005 4 int n, k, num[2] 阅读全文
posted @ 2012-09-20 07:43 Burn_E 阅读(206) 评论(0) 推荐(0)
摘要:又是POJ原题,这网赛是有多少原题。。一些人站队,但有的一排站了多个人,每个人告诉你他前面有多少个人,后面有多少个人,问说实话的人最多有多少个。 比赛的时候没想法,大叔过的这一题。赛后看了解题报告才发现思想原来是那么简单。p[i][j]表示说前面i个人,后面j个人这个区间说实话的最大人数,有一个人说i,j就加一,注意不能超过n-i-j,然后d[i]表示i前面区间都已经确定时说实话的最大人数。d[i]=max(d[j]+p[j][n-i])。 1 #include <stdio.h> 2 #include <string.h> 3 #include <algorit 阅读全文
posted @ 2012-09-20 07:34 Burn_E 阅读(176) 评论(0) 推荐(0)
摘要:据说也是原题,N个人,F种食物,D种饮料,每种食物和饮料都有一定的数量,而每个人都有自己喜欢的食物和饮料,当一个人拿到自己喜欢的食物之一以及喜欢的饮料之一时,这个人能够被满足。求最多能满足多少人。 看到题就觉得是网络流,但一时没想到怎么建图,斌牛一看题就说是原题,然后啪啪啪敲完键盘就过了。。 食物放左边,饮料放右边,人放在中间,拆成两个点,点间流量为一,然后左点连喜欢的食物,右点连喜欢的饮料,再加个源点和汇点,做一遍网络流就OK了。。 1 #include <string.h> 2 #include <stdio.h> 3 #include <algorithm& 阅读全文
posted @ 2012-09-20 07:25 Burn_E 阅读(169) 评论(0) 推荐(0)
摘要:求g(g(g(n))) mod 109 + 7,已知g(n) = 3g(n - 1) + g(n - 2),g(1) = 1,g(0) = 0。 因为每两个数只和前两个数有关,所以模之后必然会出现循环节。现在只知道最外层的循环节,所以要把内两层的循环节暴力出来。有了三层的循环节之后用二分矩阵就可以了。 1 #include <string.h> 2 #include <stdio.h> 3 typedef long long LL; 4 struct matrix{ 5 LL mz[2][2]; 6 void init(int type){ 7 memse... 阅读全文
posted @ 2012-09-20 07:18 Burn_E 阅读(162) 评论(0) 推荐(0)
摘要:图上的每个点有权值,求使从起点无法到达终点去掉的权值和最小。 因为权值在点上,所以要进行拆点。将i点拆为2i和2i+1。然后流量统一从偶数点进,奇数点出,点之间连流量为点权的有向边,无向边拆成两条有向边,分别向两个端点连两条流量为无穷大的有向边,如下图所示。 1 #include <string.h> 2 #include <stdio.h> 3 #include <algorithm> 4 #define MAXN 500 5 #define MAXE 100000 6 #define INF 0x3f3f3f3f 7 struct edge{ 8 int 阅读全文
posted @ 2012-09-20 07:12 Burn_E 阅读(222) 评论(0) 推荐(0)
摘要:维护一个可以插入删除的有序序列,每次询问序列中位置mod5=3的数的和。 CodeForces原题,因为时限给的太宽,数据太水,STL可以暴力过。 用线段树和平衡树都可以做这题,线段树需要先离散化,然后每个区间五个标记分别保存到这个区间左端点的距离mod5=0~4的和,以及一个标记保存这个区间数的个数。合并区间的时候,左儿子因为左端点相同可以直接合并,而右儿子需要推一下,假设左儿子有Num个元素,右儿子本来Mod5=K的点,合并之后到左端点Mod5的值为(num%5+K)%5,所以sum[p][i] = sum[p<<1][i] + sum[p<<1|1][(i-num 阅读全文
posted @ 2012-09-20 06:58 Burn_E 阅读(176) 评论(0) 推荐(0)
摘要:直接map就水过去了。。 1 #include <map> 2 #include <string> 3 #include <stdio.h> 4 #include <iostream> 5 using namespace std; 6 map<string,int> mp; 7 string s[5005],s1; 8 int cas,n,m,cc[]={2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7,7,8,8,8,9,9,9,9}; 9 main(){10 for(cin>>cas;cas--; 阅读全文
posted @ 2012-09-14 11:53 Burn_E 阅读(132) 评论(0) 推荐(0)
摘要:这题比较容易想到的做法是splay,但是splay写起来比较麻烦而且每次操作都有LogN的复杂度,双向链表也是可以实现的,但实践起来比较麻烦,尤其是翻转操作。。。 可以发现每次L或者R都是移动一位的,我们可以用更简单的数据结构来实现,用两个栈分别存L左边和R右边的数据,L和R中间的数据使用一个双端队列来保存,因为涉及到翻转操作,要用一个dir来表示当前的双端队列哪边是头哪边是尾。。。 对于题目中给出的七种操作,都可以在O(1)的复杂度内实现,为了描述方便,左栈代表L左边数的栈,右栈代表R右边数的栈。 1,MoveLeft L/R 左移左指针就是把左栈中栈顶的数弹到双端队列头部,左移... 阅读全文
posted @ 2012-09-14 11:51 Burn_E 阅读(376) 评论(0) 推荐(0)
摘要:给出N个城市,城市之间的路径需要一定的花费。其中一些城市(H<=15)是必达的,在这些城市可以打工赚钱,但前提是有足够的钱购买这些城市的工作许可。问是否能获得所有的许可并且最终回到起点。 这题和我之前出过的一个题很像。。http://acm.csu.edu.cn/onlinejudge/problem.php?id=1175 先对这H个点做一遍最短路,这题的点比较少,直接用FLOYD,然后对这H个点用哈密顿回路DP就可以了。 需要注意的是一个城市允许经过多次,如果第一次来这个城市时不够钱购买工作许可可以在其他城市工作赚了钱之后再回来拿。。。 1 #include <string.. 阅读全文
posted @ 2012-09-14 11:24 Burn_E 阅读(232) 评论(0) 推荐(0)
摘要:有一个栈,你可以把这个栈中的数吐到另一个栈中去,然后每次可以从两个栈中选择一个数出栈,使∑num[i]*(i-1)最小,num[i]代表第i个出栈的数。 比赛的时候一直没想法,看了解题报告才恍然大悟。。对于每个区间,枚举第一个人是第几个出栈的,假设区间是[L,R],第一个人是i个出栈的,那么这个栈就被分成了三部分,[L,L],[L+1,L+i],[L+i+1,R],对后面两个区间看作子问题继续DP,注意对后面一个区间要加上(sum[R]-sum[L+i-1])*i,sum[i]表示前缀和。 1 #include <stdio.h> 2 #include <string.h&g 阅读全文
posted @ 2012-09-14 11:12 Burn_E 阅读(200) 评论(0) 推荐(0)