随笔分类 - HDOJ
摘要:给出M个不同的数,每个数有无穷多个。从中选N个组成环,问最大公约数为1的方案有多少种。 上一题是这题的基础,不同的是每个数可以选多个,tot[i]表示m个数中i的倍数有多少个,那么用构成长度为l最大公约数为i的倍数的方案有tot[i]^l种,之后再用容斥求一下最大公约数为1的方案即可。 另外要考虑循环同构,套一个Burnside就行了,坑的就是N是10007倍数的情况,WA了N次。。要将MOD*n。。 1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 #define MAX
阅读全文
摘要:枚举统计所有<=L/2的数,在找到是否存在一个>L/2的数使所有其它数加上它都不大于L即可。 注意枚举的时候把模运算进行转化。 1 #include <stdio.h> 2 #include <string.h> 3 #define INF 0x7fffffff 4 typedef __int64 LL; 5 int n, l, a, b, mod; 6 int main(){ 7 //freopen("test.in", "r", stdin); 8 while (scanf("%d%d%d%d%d&quo
阅读全文
摘要:用1~N构造一个序列,使max(最长上升子序列,最长下降子序列)最小,并且字典序最小。 最近做的构造题好多,这种1~N的序列大多是sqrt(n)的构造。。 官方题解: 其实这是个挺有趣的题,你需要构造一个 1..N 的排列,使得其最长上升序列的长度和最长下降序列的长度的最大值最小。应该比较容易能够想到这个答案是 sqrt(N) 级别的,这个结论的证明可以参考吴文虎的那本组合数学 p21 。 当然这还没有结束,怎么找字典序最小的那个解呢?先看看完全平方数吧,对于 4 ,我们有 2 1 4 3 ,对于 9 ,我们有 3 2 1 6 5 4 9 8 7 。嗯,完全平方数的规...
阅读全文
摘要:给出一个N*M的矩阵,其中有些格子不可走。一个机器人想要通过命令从起点走到终点,命令分为三种,左转右转和前进,先给出一个只包含左转和右转的指令序列,问是否能够通过增加有限个的前进指令,使该指令可以完成从起点到终点。 N和M的范围是1000,指令长度为1000000,必然有巧妙的方法。 首先,执行完每个命令的朝向肯定是固定的,所以如果能更早的到达某一个格子的某个方向,必然会选择最早的到达方法,问题转化为求最早到达d[x][y][d]这个状态所需要的指令数。这里可以看作最短路的问题,用一个优先队列来解决,但是每次选择是LogN的。 有更优的方法在O(1)的复杂度实现选择,处理出每个命令下...
阅读全文
摘要:N层楼,每层M个有分数的格子,一开始在第一层的S点,每层最多不能连续走T个就必须下楼,求到达最底层能获得的最大分数。 经典的单调队列优化问题,用A[i][j]表示前缀和,now表示当前层,pre表示上一层,可以得到以下递推式: 当前层从左向右走,d[now][i]=max(d[pre][j]+A[now][i]-A[now][j-1]) = max((d[pre][j]-A[now][j-1])+A[now][i]) (j<=i) 当前层从右向左走,d[now][i]=max(d[pre][j]+A[now][j]-A[now][i-1]) = max((d[pre][j]+A[no..
阅读全文
摘要:定义两类循环,第一类就是最简单的for(int i=0;i<n;i++)....第二类就是类似与for(int i=0;i<n;i++)for(int j=i;j<n;j++)for(int k=j;k<n;k++)..一共有M<100000个循环,其中一类不超过15个,求最内层循环内的语句执行的次数。 对每一段连续的二类循环,可以想到就是求从N个数里选出M个数组成一个序列,这个序列满足不降性质,求这样的序列有多少个。 理解为插板,M个数N-1个板,在Ai和Ai-1数之间插x个板代表Ai-Ai-1=x。所以答案就是C(M+N-1,N-1)。 组合数比较大,因为给的
阅读全文
摘要:N个楼高度1~N,在最前面可以看到F栋楼,最后面可以看到B栋楼,求有多少种可能的排列。 对某几个数组成的集合,可以定义一个最大表示法,就是最大的数在最前面。F+B栋楼,去掉N之后,就是F+B-2个集合,选中其中的B-1个在前方按集合最大值升序排列,后方反之。然后对每个集合,不管怎样排列,看到的都是最大的那一个,可以想到是第一类stirling数,用N-1个数组成F+B-2个圈的排列数。 所以答案就是C(F+B-2,F-1)*S(N-1,F+B-2)。O(N^2)预处理,O(1)查询。 1 #include <string.h> 2 #include <stdio.h>
阅读全文
摘要:有K个数D1~DK,一开始S0=0,每个人可以报一个数Si+1=Si-1+Dj或者Si+1=Si-Dj(1<=j<K),并且满足Si<=N及Si>Si-2,最先不能报数者输。 如果自己在某回合报的不是最小数,那么对方就可以减掉最小数使S变小,因为要满足条件自己又要加上一个比最小数大的数,对方又可以减掉最小数。。。这样每次使数变大的都是自己,必输。 所以最优策略就是一直报最小数。 1 #include <stdio.h> 2 #include <string.h> 3 #include <queue> 4 #define INF 0x3
阅读全文
摘要:给出两个N*N的矩阵C和X,其中X是一个01矩阵,并满足以下几条,求最小的∑Cij*Xij(1<=i,j<=n)。 1.X12+X13+...X1n=1 2.X1n+X2n+...Xn-1n=1 3.for each i (1<i<n), satisfies ∑Xki (1<=k<=n)=∑Xij (1<=j<=n). 如果将C看作邻接矩阵,Xij=1实际上就是选择C中的对应边。那选出的这些点和边有什么特点呢,根据C的条件可以看出,顶点1的出度为1,顶点N的入度为1,其它点的入度=出度。这实际上就构成了一条从1到N的路径,或者从1出发走过一个环回
阅读全文
摘要:求C(n+m,m)%p ,n和m很大,p是小于10^5的素数。 LUCAS定理。 1 #include <string.h> 2 #include <stdio.h> 3 typedef long long LL; 4 int cas; 5 LL n, m, p; 6 LL fac[100005]; 7 LL powmod(LL a, LL b, LL p){ 8 LL ans = 1, tmp = a; 9 for (; b; b >>= 1, tmp = tmp * tmp % p)10 if (b&1) ans = ans * tmp % p;
阅读全文
摘要:求区间内该数的值模该数的各位数字和为0的数有多少个。 没想到简洁的状态,d[i][s][mod][r]表示i位,前缀和为s,总和为mod,%mod=r的数有多少个。 1 #include <string.h> 2 #include <stdio.h> 3 #include <algorithm> 4 //i位,前缀和为s,总和为mod,%mod=r的数有多少个 5 int num[10], len, ans, sum, d[10][82][82][82]; 6 int dfs(int i, int s, int mod, int r, bool e){ 7
阅读全文
摘要:一堆N个石头,每人每回合可以将其分成K和N^K两堆,并且满足K<N且N^K<N,最后不能移动的人失败。 用F(N)代表N里面1的个数,容易推出F(N)和F(K)+F(N^K)的奇偶性相同。最后的终态是F(X)=1,即最后的堆数只和1的个数有关。所以如果F(N)=奇数,一定经过偶数次操作到达终态,如果F(N)是偶数,一定经过奇数次操作到达终态。 所以只要看1的个数为奇数的堆有多少个就知道输赢了。 1 #include <string.h> 2 #include <stdio.h> 3 #include <algorithm> 4 using nam
阅读全文
摘要:长度为N的格子,Alice和Bob各占了最左边以及最右边K个格子,每回合每人可以选择一个棋子往对面最近的一个空格移动。最先不能移动的人获得胜利。 官方题解: k=1时 很容易看出,n为奇数则后手获胜,n为偶数则先手获胜 k>1时 如果n=2*k+1,则棋 盘中只有一个空白的格子,每次移动必须移动到当前的空白格子上。先手方可以先随意选择一颗棋子占据中间的位置,然后双方互有移动,移动过程中双方肯定都会 选择一颗在己方半场的棋子移动到对方半场里。直到后手方还剩下一颗己方半场的棋子时,先手方把占据中间的棋子移动到对方半场,此时后手方必须移动剩下的这 颗棋子到空出的中间的格子里,先手方再把...
阅读全文
摘要:之前无聊时还想到过这个东西,没想到多校就出出来了。。 结论是面积最大时正好是圆的内接四边形,证明网上可以找到。。 1 #include <stdio.h> 2 #include <math.h> 3 #include <algorithm> 4 double l[4]; 5 int cas; 6 double hl(){ 7 double p=(l[0]+l[1]+l[2]+l[3]) / 2; 8 return sqrt((p-l[0])*(p-l[1])*(p-l[2])*(p-l[3])); 9 }10 int main(){11 scanf(&quo
阅读全文
摘要:有N个点,每次可以从起点出发到1或者2个点然后回到起点,问走过所有的点需要的最小路程(路程定义为欧氏距离的平方)。 显然,到一个点路径为S->i->S,到两个点走过的路径为S->i->j->S。状态压缩然后枚举即可。因为和顺序无关,每次只要枚举最小的没有走的点,然后枚举到这个点返回或者到这个点再去另一个点之后返回的路径长度,相同的状态取最小值即可。 1 #include <string.h> 2 #include <stdio.h> 3 #include <algorithm> 4 #define INF 0x3f3f3f3f
阅读全文
摘要:给出C1,C2以及若干种操作,在C1,C2直接相互赋值加减,或者C1(C2)加某个常数,或者C1(C2)乘某个常数,求最后C2的值。 可以转化成矩阵来做,根据不同的组合可以转化成13种矩阵操作,乘起来之后快速幂即可。 代码写的比较暴力。。 1 #include <stdio.h> 2 #include <string.h> 3 typedef long long LL; 4 const LL MOD = 1000000007; 5 int op[13][3][3]={ 6 { //SET C1,C1,SET C2,C2 7 {1,0,0},{0,1,0},{0,0,..
阅读全文
摘要:1~N连续的白格子,给出若干操作,分为两种,在[1,ai]里选择xi个白格子染成黑色,以及在[ai,n]里选择xi个白格子染成黑色。问把最多的格子染成黑色至少需要多少次操作。 先只考虑第一种操作,显然优先把最左边的填满,对于第二种操作,优先把最右边的填满。这就转化成了背包模型,做完两遍后合并背包即可。 1 #include <string.h> 2 #include <stdio.h> 3 #include <algorithm> 4 #define INF 0x3f3f3f3f 5 #define MAXN 1005 6 using namespace s
阅读全文
摘要:统计三角形内点的个数。 如下图所示,P(ABC)=|P(AB)+P(BC)-P(AC)|。P(AB)代表线段AB上方的点的个数 1 #include <string.h> 2 #include <stdio.h> 3 #include <algorithm> 4 #define MAXN 105 5 typedef long long LL; 6 struct pnt{ 7 LL x, y; 8 bool operator < (const pnt &p) const {return x < p.x;} 9 }pn[MAXN], pm[M
阅读全文
摘要:一个序列长度为n的序列P(1,n),构造一个序列Q,长度为N并且由1~N组成。一开始Qn对在P1的位置,接下来每秒Q都会整体右移一个位置,直到2N秒后和P没有交集。Ai代表第i秒P和Q交集元素的个数,Bi代表位置重合并且元素相等的元素个数。令Ci=max(Ai-Bi),构造一个序列,使Ci最小。 Ci最小是N-sqrt(N),官方题解说的比较详细。构造序列这个地方看了半天才看明白他是怎么构造的,对于S序列,可以这么理解:给出一个序列x[1,n],以及S(a1,a2,a3....),对应的操作就是先把x[1~a1]翻转,再把[a1+1,a1+a2+1]翻转....,比如x[]=(1,2,3...
阅读全文
摘要:经典页面调度问题,理想算法就是移出从现在开始最久未使用的。 线段树中存正在使用的页面(题中是模版。。)下次出现的时间,每次选出现时间最晚的扔掉。如果遇到一个已经在内存中的页面,也要跟新该页面在线段树中的值。 1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 #define lson l,m,p<<1 5 #define rson m+1,r,p<<1|1 6 #define calm l+r>>1 7 #define MAXN 10000
阅读全文
浙公网安备 33010602011771号