51nod算法马拉松25

A:将1~n放入n个位置,问有多少种方案使得按照题目给出的寻找m的二分程序最终找到的位置是k

可以模拟题目的二分程序,最后的位置是k,那么有log个位置的值和m的大小关系就确定了,算先放这些位置的方案数,剩下的位置放什么都行,有(n-log)!种方案
因为n的值很大,所以算阶乘可以分段打表
表的每段长度K, O(logn+n/K+K)

B:给出n个数字,问用这n个数字组成的序列有多少种满足相邻两项差的绝对值小于1

首先排序,如果值不是连续的就一定无解
然后DP,将这些数字从小到大,相同的数字一起插入,因为每个数字能插入的位置只能是两个上个数字的间隙,或者边缘且旁边是上个数字,f[i][j][k]表示插入到第i个数字,前一个数字两两有j个空隙,边缘有k个上个数字(k=0~2),合法的方案数
设有m种数字,每种数字大小c O(mc2)

C:给出A序列B序列,问有多少个区间[l,r]满足max(a[l~r])= max(b[l~r])

对于A、B序列的每个数,求出他的左边和右边第一个比他大的数的位置:
apre[i],asuf[i],bpre[i],bsuf[i](apre,asuf,bpre,bsuf都是用来处理边界的)
只考虑A序列,对于以a[i]为最大值的区间[l,r],一定有 l,r[apre[i]+1,asuf[i]1]
这时要求max(b[l~r])=a[i],所以还要记录对于每个位置i,满足b[j]=a[i],j<=i时的j最大值,记作pre[i],j>=i时j的最小值的suf[j],
这时l~r至少包含pre[i],suf[i]中的一个才能保证max(b[l~r])=a[i],同时两个序列都不能有大于a[i]的数,根据左右第一个比他大的位置找l,r的取值范围计算
细节有点多

另外,对于序列中相同的数要特殊处理,因为如果a[i]=a[j],i< j ,且i+1~j-1的最大值< a[i],这时会出现i,j的apre,asuf相同的情况,b序列没什么限制的话,有可能导致一些区间算重复,我处理的方法是找右边时,相同的数视为比a[i]大的数,找左边时,相同的数视为比a[i]小的数
O(n)

D:
定义f(T)为集合T的大小的k次幂,对于有n个元素的集合的所有子集T,
计算 (f(T)f(ST))22n ,对质数p取模(p<= 106 )
易知平均数为0
所以就是计算 TS(f(T)f(ST))2(Mod p)
大小一样的集合可以一起算,令 g(x)=(xk(nx)k)2 所以化简柿子成
ni=0Cing(i)
套个Lucas,若n在p进制下表示为 n1,n2,n3,n4.....nm
因为当j>i时, Cji=0 ,所以柿子变成了
n1i1=1Ci1n1n2i2=1Ci2n2....nmim=1Cimnmg(im) ,后面的东西和前面无关,所以对前面求和,又因为 n1i1=1Ci1n1n2i2=1Ci2n2....nmim=1Cimnm=Cin=2n
所以柿子成了 2npModp1nmim=1Cimnmg(im)
npMod(p1)=(nModp(p1))/p
然后就可以算了
因为k已知, nk 是个积性函数,所以可以线性筛
O(p)

E:没做

F:听说是带花树开花(一般图最大权匹配),没做

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值