随笔分类 -  HDOJ

摘要:维护两个字符串,操作一可以将其中一个字符串的一个字符进行修改,操作二是查询从某一位开始的最长公共串。 这题比较简单,只要维护一个数组,0表示两个字符串该位字符相同,1表示两个字符串该位字符不同。用树状数组维护前缀和,用sum(i)表示前i个元素的和,如果要查询从第i位开始的最长公共串,只要求满足sum(x)-sum(i)==0的最大x即可,二分去找这个x就行了。复杂度比线段树去做多一个二分的log(N),但是线段树常数比树状数组大不少,所以实际效率是差不多的,而且代码要好写很多。 1 #include <stdio.h> 2 #include <string.h> 3 阅读全文
posted @ 2012-08-29 19:50 Burn_E 阅读(252) 评论(0) 推荐(0)
摘要:题目大意是说给你一个起点和终点,一个人要从起点走到终点,它不能经过一个点两次,问他不可能经过哪些点。 显然转化成能经过哪些点要好想一些,用N减去能经过的点就可以得到答案。下面的讨论都是基于求他可能经过的点有多少个。 很容易想到用双联通分量,但是建图确实比较麻烦。如下图,一个人想要从1走到3,那它可能在的点就是1,2,3。因为2是一个割点,它如果从2走到了4,想要到达3就必须再经过2,所以可以用割点和双联通建图。 用割点和双联通可以建成双联通与割点相邻的图,若右图所示。可以证明这是一棵树,因为如果存在环,这个环必然可以缩成一个点,树中任意两点有且仅有一条路径,于是只要统计这条路径上有一... 阅读全文
posted @ 2012-08-29 19:32 Burn_E 阅读(727) 评论(0) 推荐(0)
摘要:题目基于一个定理:当所有点相连的点的个数大于N/2时,一定可以构造出一条哈密顿回路,构造的复杂度是N^2。 这题的正解是构造,但很多人都是搜索过的,只能说明这题的数据比较水。sgu上有一道基本一样的题目(sgu122),这一题不用构造是过不了的。 至于构造方法,也就是3步。 STEP1:先找两个相邻点s-t,扩充出一条链直到到不能扩充为止。 STEP2:这时如果s-t不相邻,在链上找一点vi满足s与next[vi]相邻并且vi与t相邻,链转化为s-vi-t-next[vi]-s,根据鸽巢原理这个点必然存在。 STEP3:如果链中的点不足N个,就在环上开一个新口继续加点,重复STE... 阅读全文
posted @ 2012-08-29 02:15 Burn_E 阅读(365) 评论(0) 推荐(0)
摘要:题解说是容斥原理,彻底没看懂,搜到的题解也是各种简洁,就提到是容斥原理,难道大家的数学都这么好,一眼就看懂了。。。。 这题也可以用概率DP做,相比之下这种做法要容易理解的多。用一个状态表示当前抽到的卡片的状况,1代表尚未拿的卡片,有d[now]=x*d[now]+sigma(si*pi*(now^(1<<i)))+1,si表示stat中该位是0还是1,x表示停留在该状态的概率,即没拿到其它卡片的概率(没抽到卡片+抽到当前已有卡片),移项可以得到d[now]=sigma(..)/(1-x)。 1 #include <string.h> 2 #include <std 阅读全文
posted @ 2012-08-29 01:56 Burn_E 阅读(235) 评论(0) 推荐(0)
摘要:这就是大神口中的简单题,我的数论简直烂到不行,这些数学出身的家伙何必出这些恶心的数学题来难为我们呢。。 用到一个公式 A^x%P=(A^(x%phi(P)+phi[P]))%P (x>=phi[C]),phi[C]表示欧拉函数。 注意条件是x>=phi[C],但这题的x是增长很快的,很快就能满足这个条件,所以x<phi[C]这部分暴力即可。 接着继续暴力求x%phi[C]!=0的情况,很快就会出现x%phi[C]==0,并且之后一直都会满足,题目转化为求A^phi[P]%P==b,根据鸽巢原理,一定会出现长度为P循环节,于是统计循环节内满足条件的数的个数,再乘以循环节个数,然 阅读全文
posted @ 2012-08-29 01:48 Burn_E 阅读(233) 评论(0) 推荐(0)
摘要:很老的题了,一开始懒的写HASH写个二分查找还没过,后来改成HASH就A了。。 1 #include <stdio.h> 2 #include <string.h> 3 #define MOD 999997 4 #define PRI 199 5 typedef __int64 LL; 6 LL add=10000000000000000LL; 7 int cas,n; 8 LL d[5][201]; 9 LL num[MOD];10 int first[MOD],next[MOD/2],es;11 void ins(LL x,int p){12 num[es]=x,n 阅读全文
posted @ 2012-08-29 01:38 Burn_E 阅读(160) 评论(0) 推荐(0)
摘要:其实是很裸的一道题,可能是因为几乎没用过扩展KMP,只想到用后缀数组,但这题的常数卡的很厉害,不用扩展KMP应该是过不了的。 扩展KMP能求出一个串所有后缀串(即s[i...len])和模式串的最长公共前缀。于是只要将这个串复制一遍,求出该串每个后缀与其本身的最长公共前缀即可,当公共前缀>=len时,显然相等,否则只要比较下一位就能确定这个串与原串的大小关系。 至于重复串的问题,只有当这个串有循环节的时候才会产生重复串,用KMP的next数组求出最小循环节,用长度除以最小循环节得到循环节个数,在将3个答案都除以循环节个数即可。 1 #include <string.h> 2 阅读全文
posted @ 2012-08-29 01:36 Burn_E 阅读(315) 评论(0) 推荐(0)
摘要:烟囱是一个3*3的中空构造,给定烟囱的高度,问用1*1*2的砖头搭成这个烟囱有多少种方法。 首先用一个8位二进制数表示某一层的状态。枚举上下两层的状态,判断这两个状态是否可以相邻,上一层必须将下层填满,但是上层自身可以有空格。当下层为0时,上层必须为1,表示放一个竖着的矩形块,因此必须满足up_stat|low_stat=255,上层中除了竖着的砖头,都是单个或连续个横放的砖头,所以必须满足up_stat&low_stat中的连续1都是偶数个。注意循环的问题,比如0的位置是1,7位置也是1,而实际上0和7是相邻着的。 相邻层的状态会构造出一个矩阵表示转化关系,为0时代表不能相邻... 阅读全文
posted @ 2012-08-29 01:22 Burn_E 阅读(321) 评论(0) 推荐(0)
摘要:首先能够构成正方形的两个对顶点肯定在同一条对角线上,可以想到依次处理每条对角线上的点。 对于每个点,预处理出它能到的四个方向的连续1最多有多少个,记为p_up,p_down,p_left,p_right,显然,决定某一个点向右下能延伸的多少只取决于p_down和p_right中的较小值,决定某一个点向左上能延伸到多少只取决于p_up和p_left的较小值。 对于每个点,记录它能到达的最右的x轴的绝对坐标,并记录它自身的y坐标。 统计一个点和它左上的点(在对角线上)能组成多少个正方形时,只要判断有多少个点向右能和它相交即可。比如统计5,只要记录1~4中有多少点向右能和红线交叉,显然... 阅读全文
posted @ 2012-08-29 01:03 Burn_E 阅读(333) 评论(0) 推荐(0)
摘要:很明显的双向广搜,每次从M的方向搜3步,从G的方向搜1步,然后判断是否走到对方已经走过的格子即可。至于魔王的判断,直接用曼哈顿距离判断就可以了。 1 #include <string.h> 2 #include <stdio.h> 3 #include <queue> 4 #include <stdlib.h> 5 #define MAXN 805 6 struct pnt{ 7 int x,y; 8 pnt(){}; 9 pnt(int _x,int _y):x(_x),y(_y){}10 }gst[2],st,en,q[2][MAXN*MAX 阅读全文
posted @ 2012-08-28 10:17 Burn_E 阅读(261) 评论(0) 推荐(0)
摘要:虽然数很大,但是这40个数的公倍数一共才4万多个。这里用到STL会方便很多,map[i]里存放了从1~i能组成的公倍数有哪些以及每个数有多少种组成方法。 预处理一遍打个表然后每次O(n)的遍历一遍,否则会超时。 #include <string.h>#include <stdio.h>#include <map>typedef __int64 LL;int n,cas;LL m,ans;std::map<LL,LL> mp[41];std::map<LL,LL>::iterator it;LL gcd(LL a,LL b){ retu 阅读全文
posted @ 2012-08-27 23:41 Burn_E 阅读(175) 评论(0) 推荐(0)
摘要:简单线段树,开根号开几次这个数就为1了,之后再对其开根号就没有意义了。当一个区间全部为0或者1时就没有必要再去跟新这个区间了。 #include <string.h>#include <stdio.h>#include <math.h>#define lson l,m,p<<1#define rson m+1,r,p<<1|1#define calm (l+r)>>1#define MAXN 100005typedef __int64 LL;int n,q,cas=1,tu,tv,tq;LL sum[MAXN<< 阅读全文
posted @ 2012-08-27 23:35 Burn_E 阅读(146) 评论(0) 推荐(0)
摘要:一开始看范围特别小就写搜索了。。。结果自己随便出了个4*4就过不了了。。 其实就是状态压缩DP,求哈密顿回路要多少条,只是要注意判断两点是否可以划线就可以了。 #include <stdio.h>#include <string.h>#include <algorithm>typedef __int64 LL;int n,m,tot;int mz[25],bet[25][25][25],full;int zero[16],zeros,hzero[25],lowb[65536];LL d[16][65536],ans;int cant(int st,int e 阅读全文
posted @ 2012-08-27 23:24 Burn_E 阅读(222) 评论(0) 推荐(0)
摘要:ai取值范围0~1,xi取值范围0~3,所以最后异或的结果不会超过两位二进制。所以可以用一个60位的数保存30个式子的值,然后m的范围是小于22,二分一下就可以了,4^11=4*10^6,结果存下来排个序然后二分找一下就可以了。 #include <stdio.h>#include <string.h>#include <algorithm>typedef __int64 LL;int cas,n,m,ai[35][30],si[30][4];LL ans,tmp[1<<22+2];int sum[1<<22+2];int size, 阅读全文
posted @ 2012-08-27 23:14 Burn_E 阅读(302) 评论(0) 推荐(0)
摘要:简单二分,最大射击距离是必然能达到的,只要在能到达最大距离的瞬间就立刻射击可以保证时间最短。 #include <string.h>#include <stdio.h>#include <math.h>double xx1,yy1,xx2,yy2,lx,ly,vd,vb,l;double sqr(double x){return x*x;}double getdis(double xx1,double yy1,double xx2,double yy2){ return sqrt(sqr(xx1-xx2)+sqr(yy1-yy2));}int canreac 阅读全文
posted @ 2012-08-27 23:08 Burn_E 阅读(150) 评论(0) 推荐(0)
摘要:看上去很复杂的一道博弈,其实只要稍微分析就会发现情况其实很少很简单。。 斌牛的解释十分详细,我就不赘述了。。http://www.cnblogs.com/staginner/archive/2011/09/10/2173317.html 这里采用数组存储顺序可以大大减少代码的复杂程度,incs存储的是占用这个格子是会给自己留下稳定占位的个数,-1代表给对手留下了一个稳定占位。 #include<stdio.h>#include<string.h>/* Alice:15>3~6>11~14>7~8>9~10>1 Bob :15>3~6& 阅读全文
posted @ 2012-08-27 23:01 Burn_E 阅读(202) 评论(0) 推荐(0)
摘要:一开始想的很复杂,其实只要离散化一下就行了,炸x的时候将对应的y都-1,然后统计对应的y的时候将对应的已经炸掉的点减去即可。 #include <stdio.h>#include <string.h>#include <algorithm>#define MAXN 100005struct pnt{ int x,y;}px[MAXN],py[MAXN];bool cmpx(const pnt& a,const pnt& b){ return a.x<b.x||a.x==b.x&&a.y<b.y;}bool cmpy 阅读全文
posted @ 2012-08-27 22:39 Burn_E 阅读(249) 评论(0) 推荐(0)
摘要:给出如下图形,其中23个格子填有1~23,移动规则与八数码相同,给定始终态,问是否可达。 首先八个角的数字是不可能移动出去的,所以先对八个角进行判断,如果为空格则和附近格子的数进行交换,问题转化为16数码问题。和八数码类似,可以用奇偶性来判断两个状态是否可达,不同的是,将一个数上下移动会影响的整体的奇偶性,一个很好的方法就是"弓"字行统计,这样移动后奇偶性就不会改变了。#include <stdio.h>#include <string.h>int cas,a[25],b[25];//八个顶点必须相同,若为0和相邻的置换int p1[]={0,1,2 阅读全文
posted @ 2012-08-27 22:30 Burn_E 阅读(289) 评论(0) 推荐(0)
摘要:最小树形图模版题,学习了一下最小树形图。 三步走,找最小入弧,找有向环,缩环为点。#include <string.h>#include <stdio.h>#include <stdlib.h>#define INF 0x3f3f3f3f#define MAXN 1001struct edge{ int u,v,w;}e[MAXN*MAXN];int n,x,y,z,es,k,tt;int pnt[MAXN][3];int dist(int p1,int p2){ int ret=0; for(int i=0;i<3;i++)ret+=abs(pnt[ 阅读全文
posted @ 2012-08-27 22:15 Burn_E 阅读(228) 评论(0) 推荐(0)
摘要:给定一棵树,求出当x为根时y的最小儿子和最小后代各是多少。 一道中等的树形DP,首先以1为根进行DP可以求出每个节点的最小儿子和最小后代。只有当x为y的孩子时才需要讨论,否则直接输出前面DP的结果即可,这里画个图就可以看出来,下面只讨论x为y的孩子的情况。 如果y的最小儿子是x的祖宗节点,那这时该最小儿子已经变成了y的父亲,在选取最小儿子时不能在考虑这个点,应该换选次小儿子,所以每个点的次小儿子也要在DP时预处理出来,另外,这时y的原父亲在新树中已经变成了y的儿子,所以在选取最小儿子时要考虑父节点。至于最小后代,如果y不是根节点,那么最小后代必然是根节点1了,如果y节点是根节点,就先找... 阅读全文
posted @ 2012-08-27 22:08 Burn_E 阅读(237) 评论(0) 推荐(0)