2018.3.1-2018.3.8

3.1:

题1:给定一个序列a(n<=100000,a[i]<=10^9),m次询问,每次询问一个区间内数的出现次数的mex,支持单点修改。

    可修改莫队,把询问数组按照左端点所在块,右端点所在块(不带修改的莫队是右端点所在位置),上一次询问的位置3个关键字排序,修改操作要储存该位置改之前的数,改之后的数。然后我们要维护区间内 每种数出现次数 的出现次数,因为是每种数出现次数的mex,所以这个答案是不超过 根号n的

题2:WC2018的第二题

    其实这题就是个子集卷积模板题

    子集卷积大概就是这个玩意:c[i]=Σa[j]*b[k]其中满足(j^k=i且j&k=0)

    暴力做是3^n的,不过我们可以把他转换成或卷积,对于上面的3个数组,我们多记一维表示二进制中1的个数,比如说A[i][j]代表上面的a中若满足j中二进制1的个数为1,则A[i][j]=a[j],否则A[i][j]=0;

2018.3.1-2018.3.8_第1张图片

考虑一下,如果卷积出来C[i][S]有值但是不满足s的二进制中1的个数是i,那么这个状态虽然有值却是一个废状态。

题3(bzoj4766):给定一个二分图,左边的点数是N,右边的点数是M,且任意左边的点对任意右边的点都有连边,求这个图的生成树个数膜P。

    先写个行列式,然后如果数学能力强的话可以找规律找出来

    这边有个比较好的推导https://blog.sengxian.com/solutions/bzoj-4766

    注意这题膜数可能是1

题4(bzoj4765):给定一棵n个点树,点上有权,m次询问,2种类型,一是修改某个点的点权,2是询问编号在[L,R]之间的点的子树和。

    考虑分块处理,每s个点分一块,设块总数是nn,用cnt[i][j](1<=i<=nn,1<=j<=n)代表考虑第i个块中的点,点j的权值被算了多少次,那么可以算出w[i]代表第i个块的所有点的子树权值和,那么对于一个询问,可以直接把整块的w[i]直接累加,对于零散的,可以用树状数组一个个查,时间复杂度是O(nS log n)。对于一个修改操作,我们对于所有的块,已经知道了x(修改点)的贡献次数,那么我们直接加上cnt[i][x]*相差的值,树状数组直接修改

    如果我们用sum[i]表示dfs序中前i个块的权值和,s[i][j]表示dfs序第i个块中前j个点的权值和,那么对于询问中那些零散的点,我们可以在每个点O(1)次运算(前缀和相减)求出一个点子树权值和,那么修改操作就是先考虑块内修改,再考虑对后面的块的修改。这样复杂度可以去掉一个log,但是常数变大了细节也多了。


3.2


题1(CF 917C):有n个石头排成一列,一开始有x只蝌蚪在前x个石头,每只蝌蚪最多可以跳k格,c[i]表示跳i个需要花费的代价,然后有q个特殊格子,跳到这几个格子需要额外花费一定的代价w(可能为负,不过无所屌谓)1<=x<=k<=8,n<=10^8,q<=25,c[i],w[i]<=10^8。

暴力转移就是设f[i][S],代表最后一只青蛙跳到第i位,然后然后i-k+1到i的状态(为1代表这一位有青蛙,但是第i位一定要有青蛙),然后我们可以构造出转移矩阵,假如没有q个特殊格子,那么我们就可以像矩阵快速幂那样,把传统矩阵乘法的+改成取最小值,*改成+

        然后如果有特殊格子,那么就每次快速幂到特殊格子前一个,然后对于特殊格子,暴力转移,就是枚举那只青蛙跳到这一位。这题要注意的就是第i位一定要有青蛙,这样设计状态可以省略很多特判

题2(bzoj1005):给定n个点的树,有些点有度数限制有些没有,求满足条件的树的个数

    考虑prufer序列,一个N个点的树prufer序列长度为n-2,一个点在prufer中的出现次数为度数-1,那么记所有 有度数 的点的(Σdu[i]-1)=m,那么不考虑无度数限制的点,答案就是C(n-2,m)*(m!)/(π(du[i]-1)!)

    再考虑有度数的点的限制,显然就是在剩下的(n-2-m)个位置中随便填,记无度数限制的点的个数为tot,那么这部分的答案就是tot^(n-2-m)

    所以总的答案是C(n-2,m)*(m!)/((Σdu[i]-1)!)*tot^(n-2-m),答案很大,用高精度即可,注意把高精度的数组开大点

题3(bzoj4596),给定一个n个点的树(n<=17),然后给出n-1个组,每组有若干边,要求每组选一条边使得该图成为一个生成树。

    直观的思路是容斥,假如我们把所有的边(不管是不是在一个组)运用矩阵树定理求出生成树的数量,那代表的是:至多n个组的边组成了生成树,而我们要求的是恰好n个组的生成树数量。

    记f[i]表示至多i个组的生成树数量,那么显然对于一个i(1<=i<=n),若i和n同奇偶,贡献是f[i],否则就是-f[i]

3.3

题1:(bzoj3926)对于一个n个点的树,每个点有一个字符,定义路径为某2点间的节点上的字符组成字符串,求树上有多少条本质不同的路径,n<=10^5,叶子节点数<=20

    以每个叶子节点为根构建trie树,并把它们合并(其实就是多加一个根节点),对这个trie树求出后缀自动机,对于每个点

它对答案的贡献是dis[x]-dis[fa[x]]。(反正我对sam不太理解,舟神告诉我说trie的sam就是把上个节点设成它trie树的fa)

题2:(bzoj2322)对于一个图,边权<10^18,点数<5000, 边数<20000, 从1号点出发,可多次经过一条边,求出有多少种不同的路径长度,路径长度的定义为经过边权的异或和,以及q次询问,每次询问删掉一条边之后不同路径长度(一条路径被删除就永久被删除了)

    个人感觉是个神仙题。

    从答案的角度分析,答案=(所有本质不同的路径数)*2^(本质不同的环的个数)-1,注意本质不同的路径包括哪里都不走,所以最后要-1。具体本质不同是什么意思呢?

    我们最终得到的不简单的路径的异或和=任意一条简单路径的异或和^任意一些环的异或和,所以两条简单路径本质不同当且仅当它们用线性基消元后,得到的值不同(即代表元不同,对于一个数w,我们要求出代表元,对于线性基中的元素,我们从高到低考虑,若异或上当前元素

    好了,分析了这么多,现在我们终于可以得出一个可行的做法了:当加入边(a,b)时:

1.若a,b都已经被访问过(或者说加入的是一条非树边),我们此时得到了一个简单环,将这个简单环的异或和放到线性基中消元,如果没有消成0,那就说明我们应该将这个圆加入到线性基中去,直接把它加入到线性基中对应的位置就行了。但是注意一点,更改线性基后,之前的路径并没有被这条边消元,所以要把set里的边一个一个取出来,重新消元再塞回去。

题3(bzoj2689):n个点形成一个环,环内有n-3条边,选一个点可以控制它连出去的边,求控制所有的边至少需要多少点

问题等价于每个三角形里至少选择两个点。
考虑拓扑,每次取出度数为2的点xx,代表一个只与最多一个三角形相邻的三角形(x,y,z)(x,y,z)。
如果x已选,那么(x,y)(x,y)以及(x,z)(x,z)都已经被覆盖,无需再选其它点。
否则因为至少要选两个点,选yy和zz一定最优。

时间复杂度O(n+m)。

题4:bzoj4709:给个序列,分为若干段,每个段的价值是,选一个数x, 对于这段中x出现的次数记为y,价值为x*y*y

dp的最优方法肯定是,首尾的数都相同,选择的x是首或尾的那个数

对每个数分别考虑,对于j

3.4

    题1:bzoj1006,弦图染色,要求相邻的点必须是不同的颜色,弦图的定义在我个人的理解就是一个图中的环必然由若干三元环构成。

    根据论文内容,对于弦图我们要求出一个完美消除序列,具体过程大概是这样的:我们给每个点都设一个f值,一开始所有的f值都是0,第i次取出一个f值最大的点v,那么这个完美消除序列的第i项就是v,然后把v相连的f值都加上1,重复这个过程N次。

    染色过程,就是按照完美消除序列,对于每个v,求出与它相连的并且已经被染色的点,求这些颜色的mex就是这个点的颜色。

    题2:给出一个由小写字母组成的字符串S,问有多少由小写字母构成的字条串S',满足  1:|S|'=|S|  2:S'[L..R]是回文串,当且仅当S[L..R]是回文串,答案对10^9+7取模。

    对于每个字符开一个节点,然后根据manacher求回文串的时候,把必须相等的用一个并查集搞起来,然后如果第x和第y个位置必须不等,那么x所在并查集向y所在并查集连边。可以证明这样构成了一个弦图(虽然我不会证明)

    然后对这个弦图求出完美消除序列,根据完美消除序列,每次取出v,枚举v相邻的并且已经访问过的节点,记个数为tot,那么ans*=tot,最后ans就是答案

    题3:bzoj4445:凸n边形,N个顶点按照逆时针从0~n-l编号。现在小凸随机站在操场中的某个位置,标记为P点。将P点与n个顶点各连一条边,形成N个三角形。如果这时P点,0号点,1号点形成的三角形的面积是N个三角形中最小的一个,小凸则认为这是一次正确站位。现在小凸想知道他一次站位正确的概率是多少。

    把0,1这2个三角形的面积和其他n个的关系列出来,会发现每个都是一条直线的形式,然后因为限制在这个多变形内,然后再把多边形的边加上去,求个半平面交。

    有个难点,比如说这个直线是Ax+By+C<=0,那么我们应该如何选取边上的2个点?直线Ax+By+C<=0代表的区域是这个直线从小到大看的左侧,注意取2个点的顺序。

3.5

    题1:bzoj4962,给定一个字符集大小为N 的串,求有多少长度为偶数的连续子串前一半和后一半循环同构

    循环同构的串必然能表示成uvvu,然后考虑u比v大和v比u大的情况。

    若v比u大,我们可以通过枚举uvvu的分解点,然后向两边扩展,用字符串哈希判断是否合法。

    若u比v大,那么我们对于原串的每个后缀,用kmp求出next数组,然后我们就相当于找一个border满足长度是我们枚举的这个串的一半。

    根据border理论,next数组必然是由log个等差数列构成,用总长度(N)减去任何一个等差数列的和sum,那么n-sum<=0.67N,那么最多跳2个等差数列就好了。

    题2:bzoj4567,给定n个串,要把他们依次放入一个集合中,若串i要放进去,必须满足这N个串中所有i的后缀的串要放进去,假如串i在t1时刻放入集合,i的最大一个后缀在t2时刻放入,那么产生代价是t1-t2,目标是最小化这个代价。

    首先考虑把串反转,然后依次插入trie树,在代表每个串末尾的地方打上标记,那么把trie树缩点,那么问题转化成了,用0到N给每个点标号,0号点必须是0,每个点的代价为w[i]-w[fa[i]],最小化这个代价,

    手玩几个小数据,结论大概就是,按照dfs序,每次按照size从小到大的顺序标号。

    题3:bzoj4571,给定一堆数字a[],m个询问,每次给定b,x,l,r问b ^ (a[i]+x) (其中l<=i<=r)的最大值

    从高位到低位考虑,我们尽量让这位是1,然后我们就相当于查询这个区间内是否存在权值在某个范围的数,从高位到低位,这个权值区间会渐渐缩小。

3.6

    题1:bzoj4570,给定n个妖怪,每个妖怪有2个属性值x[i],y[i],妖怪可以降低自己k×a点攻击力,提升k×b点防御力或者,提升自己k×a点攻击力,降低k×b点防御力,a,b属于正实数,k为任意实数,但是x和y必须始终非负,妖怪在环境(a,b)中的战斗力为妖怪在该种环境中能达到的最大攻击力和最大防御力之和,一组正实数(a,b)使得n只妖怪在该环境下最强战斗力最低,输出最低的最强战斗力。

    转化一下模型,把x,y看成平面上的点,相当于过x,y引一条斜率为-b/a的直线,这条直线在x,y轴的截距之和就是在(a,b)环境下的战斗力。

    那么算法就很显然了,先对于所有点求一个上凸包,然后上凸包的每个点都有一个最强战斗力的斜率范围,也就是对于每个点在规定的斜率内(斜率必须是负数),求截距的最小值。

    假如过点(x0,y0)的直线斜率是k,那么这条直线方程可表示为(y-y0)=k(x-x0),令y=0,则x=-y0/k+x0,令x=0,则y=-kx0+y0,那么就是要最小化函数-y0/k+x0-kx0+y0,这并不是一个常见的函数,我的思路是求导:y0/(k*k)-x0,令导数为0,求出极值点k=-sqrt(y0/x0)(斜率必须是负数所以舍弃正的哪项),在凸包上的每个点,如果极值点的k在合法范围,就带入判断。

    题2:bzoj4572,一个N*M的棋盘,每个位置有3种取值W B X,然后q次询问,每次给定一个模板,模板大小为2*C,要求在这个N*M的棋盘中填入W B X使得这个棋盘存在一个2*C的子矩阵和模板完全匹配,方案数MOD 10^9+7

    神仙题一道。

    暴力的思路就是枚举相邻的2行的状态转移,复杂度N*3^(2M)

    稍加优化,上面2行其实只要记录和第一行是否完全匹配,复杂度降到N*2^m*3^m

    正解是轮廓线dp,记录f[i][j][S][p][q],代表考虑到i,j这个位置,轮廓线上的状态S(即能否和第一个串匹配),第一个串匹配到p,第二个串匹配到q的方案,转移的时候,枚举第二行下一位填入什么,对于2个串预处理数组trans[i][j]代表当前匹配到i位置,填入j之后匹配到什么位置,这题思路的精髓就是,你可以通过枚举第二个串的填入状态来算出第一个串此时在轮廓线上的匹配状态。

    题3:bzoj3091,

http://blog.csdn.net/popoqqq/article/details/40823659


3.7

    不想再写了,就写一个比较好的题把

    bzoj4700.敌方有n台人形兵器,每台的攻击力为Ai,护甲值为Di。我方只有一台人形兵器,攻击力为ATK。战斗看作回合制,
每回合进程如下:
  ·1 我方选择对方某台人形兵器并攻击,令其护甲值减少ATK,
若护甲值<0则被破坏。(这里应该是<=)
  ·2 敌方每台未被破坏的人形兵器攻击我方基地造成Ai点损失。
但是,在第一回合开始之前,某两台敌方的人形兵器被干掉了(秒杀)。问最好情况下,我方基地会受到多少点损
失。

    先考虑没有秒杀的情况,用a[i]表示第i个兵器的攻击,b[i]表示我们要进行的攻击次数,然后我们要安排一个顺序,考虑一下

    若a[i]*(b[i]-1)+a[i+1]*(b[i]+b[i+1]-1)<=a[i+1]*(b[i+1]-1)+a[i]*(b[i]+b[i+1]-1)

    根据上面的式子确定顺序

    然后我们用pre[i]表示前i台机器造成的伤害,suf[i]表示后i台机器造成的伤害,sum[i]表示a[i]的前缀和,然后答案就是要最小化

    pre[i-1]+(suf[i+1]-suf[j])-(sum[j-1]-sum[i])*b[i]+suf[j+1]-(sum[n]-sum[j])*(b[i]+b[j])

   =pre[i-1]+suf[i+1]-suf[j]-sum[j-1]*b[i]+sum[i]*b[i]+suf[j+1]-sum[n]*b[i]-sum[n]*b[j]+sum[j]*b[i]+sum[j]*b[j]

   =(pre[i-1]+suf[i+1]+sum[i]*b[i]-sum[n]*b[i])+(suf[j+1]-suf[j]-sum[n]*b[j]+sum[j]*b[j])-sum[j-1]*b[i]+sum[j]+b[i]

=(pre[i-1]+suf[i+1]+sum[i]*b[i]-sum[n]*b[i])+(suf[j+1]-suf[j]-sum[n]*b[j]+sum[j]*b[j])+a[j]*b[i];

另f[i] = pre[i-1]+suf[i+1]+sum[i]*b[i]-sum[n]*b[i], g[j] = suf[j+1]-suf[j]-sum[n]*b[j]+sum[j]*b[j]

那么最大化f[i]+g[j]+a[j]*b[i](i

我的做法是分治,把右边的排序一下,类似凸包的求一下,然后左边的二分一下,复杂度O(n log n log n)。


你可能感兴趣的:(学习记录)