20190710B组

20190710B组

T1:100(100)

赛时:

怎么现在比赛第一题都是数论?

这种一看就是规律题。

于是,我先将Fibonacci sequence打出来。

发现每15000个一个周期。

之后,分类讨论一下就行了。

赛后:

对于80%的数据,根据递推式用O(n)的方法就可以了。对于100%的数据,显然要用到矩阵方法,这里介绍两种思路。

设F(n),S(n)分别为Fibonacci sequence的第n项和前n项和,求第x~y项的和相当于求S(y)-S(x-1),于是问题变成了怎么求S(y)和S(x-1)。

  1. 求出S(n)的通项,和F(n)的通项比较,可以发现S(n)=F(n+2)-1,于是就用矩阵乘法求出数列的第N+2项。但这样的方法在比赛中不可取,因为,,显然除非你的手算能力足够强,否则这需要浪费大量时间才能推倒出来。当然,由于S(n)=F(n+2)-1规律还是优美的,善于观察的同写几项出来就可以发现规律.
  2. 根据F(n)=F(n-1)+F(n-2),S(n)=S(n-1)+F(n),我们可以按如下方法构造一个矩阵。

这种方法比较直观,对矩阵乘法比较熟悉的同学应该很容易想到.

算法:

数论

T2:60(50)

赛时:

又事一道数论,可是就没有前面几题那么简单了。

经过一波乱推,一点效果都没有。

最后只能打一个暴力。

感谢出题人,说好的50分,却给了60分。

赛后:

对于50%的数据,直接枚举答案判断即可,对于80%的数据,用未优化的容斥原理可以解决,对于100%的数据,就要把一些冗余的计算省去才可以解决。

对于整数倍数的问题,一般很容易想到用容斥原理去做,对于这道题也是一样的。由于题目答案不容易直接得出,而且答案又有明显的有序性,于是我们可以二分答案,把原问题转化成一个判定问题。

现在对于二分的答案ans,现在就是要求在[1,ans]这个范围内,有多少个数满足条件。对于这个问题,我们可以枚举N个数当中的,设为[1,ans]中有多少个数仅能被数整除,那么[1,ans]中,满足题目条件的答案是。如果,那么ans就要加大,否则就减小。这样的时间复杂度是,对于N=15这样的数据显然是难以在规定时间内出解,所以我们要进一步优化。

其实枚举每一个,然后求出,在这个过程中有很多冗余的计算。我们在对每个做容斥原理的时候可以发现,如果连同有k个数求出它们的交集,如果k是奇数,那么答案就加上这个交集,如果是偶数,则答案减去这个交集。对于其余的k-1个数,我们+-的都是同样一个数,所以就没必要枚举所有的单独求解。对于现在求出来的k个数的交集,如果k是奇数,那么答案加上k*交集大小,如果k是偶数,那么答案就减去k*交集大小,这样的出来的结果是一样的。时间复杂度就变成,这样就可以在规定时间内出解了。

其实没必要每次做容斥原理的时候都要去做GCD,GCD可以在开始的时候做一个预处理,f[state]表示状态为state(state是二进制化成10进制)的数的gcd是多少,这个预处理可以在2^n就可以做出来,然后做容斥原理的时候只就不需要重复做GCD了,时间复杂度变成,很完美地解决这个题目。所以,这样与处理后即使不去掉冗余计算的方法的时间复杂度变成,也可以在规定时间内出解。

算法:

数论

T3:50(50)

赛时:

终于出了一道字符串的题。

但是,太难了。

只好又打暴力。

幸好出题人有良心,暴力还有50分。

其实是一道状压dp题。

赛后:

对于50%的数据,枚举k的全排列,然后生成新的字符串,然后按照题目要求做即可。对于100%的数据,要用到状态压缩Dp做。

首先可以发现,对于Len div k个块,他们基本是互不影响的,只是在头尾链接的时候有影响。而且在新的字符串中,每个块里面字母的排列顺序都是一样的,于是我们可以设S1[i][j]第i个字符和第j个字符不同个块的总和,S2[i][j]表示相邻两个块之间,前一个块的第i个字符和后一个块的第j个字符不相同的情况的总和。

于是我们就可以设f[i][j]当前排列以j结尾,在排列中的元素的状态为i(i是二进制转化成的10进制)的压缩后最小长度是多少。F[i][j]=min(f[i-(2^x)][x]+S1[k][j]);其中i and (2^x)<>0,且i and 2^j=0 于是我们就可以对于每个位置开头,都做一次Dp,求出f[][],然后枚举f[2^k-1][j],ans=min(f[2^k-1][j]+S2[start][j]),start就是当前枚举的起始位置,初始状态是f[2^start][start]=1;这个Dp的时间复杂度是O(*(Len/k)+)。

算法:

状压dp

T4:20(100)

赛时:

果然最后一题,比赛还是要出一道图论。

图论总离不开最短路和树。

这题题目上说树,其实一点关系都没有。

直接最短路,并统计到这个点的最优解的方案数。

并用乘法原理,就AC了。

赛后:

给一个最多50个点的带权无向联通图,无自环和重边,现在要去掉图上的一些边,使得图变成一棵树,并且在结果的树上,每个点到点0的距离等于在原图中每个点到点0的最短距离。问可以生成多少个不同的树。

个人比较喜欢这题,做之前需要好好思考一下。首先考虑离0点最近的那个点,一定和0点只连着一条边,则这条边是必选的;然后考察第二近的点,一种可能是和0点直接连的边比较近,一种可能是经过刚才最近的那个点再到0点的路比较近,不管是哪一种,选择都是唯一的,而剩下第三种可能是两者距离相同,这样的话两者选且只能选一个。以此类推,假设现在已经构造好了前k个点的一棵子树,看剩余点中到0点最近的点,这个点到0点有k种方法(分别是和那k个点连边),其中有m个是可以保持最短距离的,则这一步可选的边数就是m。一直构造,把方法数累乘,就能得到最后的结果。整个过程可以很好的符合dijkstra的过程,而生成树的步骤和prim如出一辙。

算法:

最短路

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章