从现在起,最后几天刷题,从7月1日开始复习以前做过的题目和考试,整理模板和经典题目
622E 贪心
考虑每个1的子节点,把子树中所有叶子节点按深度排序,那么贪心的让深度小的叶子先上去
dp[i]表示i最快用多久到根
dp[i]=max{dp[i-1]+1,dep[i]}
最后这一个转移方程没有想到啊,挺巧妙的
666C 组合+dp
容易发现,答案与字符串的构成无关,只与字符串的长度有关
设m为模板串的长度,n为匹配串的长度
ans=∑C(i-1,m-1)*25^(i-m)*26^(n-i)
以最靠前的子序列为标准,枚举最后一个点的位置i,在前面的i-1个地方选m-1个来填数,其中s[i]和s[i+1]之间,所有的数都不等于s[i+1],最后一个点之后的字母可以随意选择
但是暴力是O(mn)的,如何优化?
当长度小于等于sqrt(n)时,预处理出答案
当长度大于sqrt(n)时,这样的串不会超过sqrt(n)个,每次暴力递推长度为i的方案数
复杂度O(nsqrt(n))
660E 组合数学
与上题相似,不考虑长度为0的子序列,通过枚举最后一个点的位置,确定包含每个长度的个数
ans=∑m^i*m^(n-j)*(m-1)^(j-i)*C(j-1,i-1) (1<=i<=n,i<=j<=n)
=∑m^(n-j+i)*(m-1)^(j-i)*C(j-1,i-1)
改变枚举对象,s=n-j+i(1<=s<=n)
=∑m^s*(m-1)^(n-s)*∑C(n-s+i,i) (0<=i<s)
有一个公式∑C(r+k,k)(k<=n)=C(r+n+1,r+1)
∑C(n-s+i,i)=C(n,s-1)
ans=∑m^s*(m-1)^(n-s)*C(n,s-1)
O(n)直接计算即可
671C 奇怪的计数问题
考虑计算Hi表示答案小于等于i的(l,r)对数
对于确定的i,容易发现f(l,r)随着r增加,单调递减
对于每一个l,维护nxt[l]表示最小的位置满足f(l,nxt[l])<=i
Hi=∑n-nxt[l]+1=n(n+1)-∑nxt[l]
倒序枚举i,当i+1变成i时,考虑nxt[l]的变化
答案等于i时,满足至少存在两个i的倍数
要使答案小于i,则必须满足最多只存在一个i的倍数
记四个数l1,l2,r1,r2分别表示所有数中是i的倍数的最靠左的数、次靠左的数、最靠右的数、次靠右的数,[l,r]表示当前区间
若l<l1,则nxt[l]=r2
若l1<=l<=l2,则nxt[l]=r1
若l>l2,则nxt[l]=n+1
对于确定的l,容易发现随着i减小,nxt[l]单调递增,所以可以转化成三个区间取max的操作
由于nxt序列是单调的,所以区间取max等价于区间赋值,可以用线段树维护
复杂度O(nsqrt(n)+nlogn)
677E 奇技淫巧
主要考察的是旋转坐标系的技巧,横竖的非常好处理
斜着的就把矩阵旋转45°,(x,y)-->(x+y,x-y)
如何判断两个数的大小?取个log判一下
675E dp+贪心
dp[n]=0
dp[i]=max{dp[j]-(a[i]-j+1)+(n-i)}
可以证明在dp[j]的计算中,[j,a[i]]中所有的点到j的距离一定是1
然后线段树优化dp
659E 贪心
不同联通块之间肯定不影响,同一个联通块中,如果是一棵树,则只有根节点计入答案,否则选择一个在环里的点当做根,对答案贡献为0
670F 构造
乱七八糟的题,除了细节多,没有别的。
先要找出一个长度合适的数列,实际最多只可能有6种长度,找到长度最小的即可。
然后,问题变成了给你一个字符串和一堆数字,要你拼成一个字典序最小的串
如果字符串以0开头,那么首先找一个非0的数放在开始,然后把0都加进去,然后加入字符串,然后升序向内加数
如果字符串非0开头,那么两种情况:
1、把字符串放到开头,升序加数
2、找一个非0的数放在开始,升序加数的过程中,把字符串加到合适的位置