已完成?/50你能优化来我的人生吗?
CF446A - DZY Loves Sequences
Description
给一个长度为 $n$ 的序列,最多可以修改一个位置的数,求最长连续上升子序列。
Solution
当 $a{i+1} > a{i-1}+2$ 时, 改变 $a_i$ 的值来使前后两段合并,反之,分别考虑$a_i$左边那段最长的和右边那段最长的。
Code
1 | const int N = 1e6+100; |
CF4D - Mysterious Present
Description
给出n个信封,这n个信封有长和宽,给出卡片的尺寸,求取能够装入卡片的最长的序列,序列满足后一个的长和宽一定大于
前一个(套娃),求最长的这个序列的长度。
Solution
$dp[i] = \max_{j=0}^{j-1} { dp[j]+1 } , { a[j].w < a[i].w \ \&\& \ a[j].h < a[i].h }$
记个pre倒序输出答案。
Code
1 | const int N = 1e6+100; |
10
10 11 12 1 2 3 14 7 15 16
串
Description
长度不超过n,且包含子序列“us”的、只由小写字母构成的字符串有多少个? 答案对10^9+7 取模。
所谓子序列,指一个字符串删除部分字符(也可以不删)得到的字符串。
例如,”unoacscc”包含子序列”us”,但”scscucu”则不包含子序列”us”
Solution
dp[i][0]无u
dp[i][1]有u无s
dp[i][2]有us
考虑状态转移。
$dp[i][0] = 25*dp[i-1][0]$ 最后有25种选择
$dp[i][1] = 25dp[i-1][1]25+dp[i][0]$前面有u的随意加,无u的加u
$dp[i][2] = dp[i-1][1]+dp[i-1][2]*26$ 有u的串最后一位加上s,加上之前us的串随意加
Code
1 | int dp[maxn][3]; |
cf#544 div.3-E. K Balanced Teams
Description
Solution
Code
1 | // She is Pretty pretty! |
美团2017年CodeM大赛-初赛A轮-合并回文子串
Description
$a,b$ 两个串保持字符顺序不变组合成字符串$c$ ,求字符串 $c$ 可能形成的最长回文子串的长度。
Solution
区间dp。
官方题解
设 $f[l1][r1][l2][r2]$ 表示$A[l1] \sim A[r1]$ 和 $B[l2] \sim B[r2]$ 是否能合并成一个回文串。
所以dp转移如图所示,
- $dp[l1][r1][l2][r2] |= dp[l1+1][r1-1][l2][r2];$
- $dp[l1][r1][l2][r2] |= dp[l1+1][r1][l2][r2-1];$
- $dp[l1][r1][l2][r2] |= dp[l1][r1][l2+1][r2-1];$
- $dp[l1][r1][l2][r2] |= dp[l1][r1-1][l2+1][r2];$
需要注意的是,当两个串选出的字符只有一个时候,认为是可以构成回文串的。(边界条件)
Complexity: $O(T\times n^4)$
Code
1 | char a[maxn], b[maxn]; |
2018年长沙理工大学程序设计竞赛-数学考试
Description
给定一个序列,选取两个不相交的长度为 k 的区间求和, MAX 这个和。
Solution
nowcoder官方题解
前缀和+暴力dp
对序列求前缀和得到 $sum$ 。设 $dp1_i$表示位置$i$ 之前最大的区间和,$dp2_i$表示位置$i$之后最大区间和。线性更新一下就OK了。
Complexity: $O(T\times n)$
Code
1 | int a[maxn], dp1[maxn], dp2[maxn], sum[maxn], n, k, ans; |
others 线段树:博客1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
using namespace std;
ll sum[422222],a[422222];
struct stree{
int p,l,r;
ll ma;
};
stree t[800020];
void build(int p,int l,int r){ //递归建立线段树
t[p].l=l,t[p].r=r; //线段树的区间左端点和右端点赋值。
if(l==r){t[p].ma=a[l];return;}
int mid=l+r>>1;
build(p*2,l,mid); //递归左儿子
build(p*2+1,mid+1,r); //递归右儿子
t[p].ma=max(t[2*p].ma,t[2*p+1].ma); //区间最大值赋值。
}
ll ask(int p,int l,int r){ //在节点p对应区间找原数组里l到r的最大值
if(t[p].l>=l&&t[p].r<=r)return t[p].ma; //若p对应区间被包含在[l,r]区间里,则直接返回。
int mid=t[p].l+t[p].r>>1;
ll ma=-1e18;
if(l<=mid)ma=max(ma,ask(p*2,l,r)); //递归找左节点
if(r>mid)ma=max(ma,ask(p*2+1,l,r)); //递归找右节点
return ma;
}
int main(){
int t;
cin>>t;
while(t--){
int n,k,i,x;
ll s=0;
cin>>n>>k;
for(i=1;i<=n;i++){
scanf("%d",&x);
s+=x;
sum[i]=s;
}
for(i=1;i<=n-k+1;i++){
a[i]=sum[i+k-1]-sum[i-1];
}
build(1,1,n-k+1);
ll ma=-1e18;
for(i=1;i<=n-2*k+1;i++){
ma=max(ma,a[i]+ask(1,i+k,n-k+1));
}
cout<<ma<<endl;
}
}
expansion
- 不限制长度—在一个数列里找两个不相交区间使得他们权值和最大
- 区间数目变多—找 $m$ 个长度为 $k$ 的不相交区间使得他们的权值和最大 $(1\leq n \leq 5000)$
- 区间数目变多且不限制长度—找 $m$ 个不相交长度不限的区间使他们的权值和最大 $(1\leq n \leq 5000)$
some ideas:
bonus1: 设 $fi$表示前 $[1,i]$ 的最大子段和, $g_i$表示 $[i,n]$ 的最大子段和。那么有$ans = \mathbb {MAX}{ f_i+g{i+1}}$
bonus2: 设 $f{i,j}$ 表示前 $i$ 个数, 分成$j$ 段长度为 $k$ 的连续子段的最大值,那么有转移方程: $f{i,j} = \mathbb{MAX} (f{i-1,j} \ , f{i-k,j-1}+si-s{i-k})$
bonus3: 设$f_{i,j,0/1}$ 表示前 $i$ 个数,分成 $j$ 段,第 $i$个不选/选的最大值,考虑第 $i$ 个是不是新开一段。于是有以下的转移方程。
Description
Solution
Code
Codeforces Round #635 (Div. 2)-E. Kaavi and Magic Spell
Description:
给定一个长度为 $n$ 的字符串 $S$ 和一个长度为 $m$ 的字符串$T$, 有 $1\le m \le n$,开始有一个空串 $A$, 接下来对 $S$ 串进行 n 次操作:
- 把 S 的首字符加到 A 的开头
- 把 S 的首字符加到 A 的结尾
问在操作过程中使得 A 的前 m 个字符为 字符串 T 的方案数。认为长度不同或者是操作序列中有某个地方不同是不同情况。
Solution:
区间 $DP$。
不妨假设 $T$ 串为 “asd”
$A$ 串为”asd*(补到与S串等长)”
定义 $dp[l][r]$ 为满足 $\forall \ l \le i \le r, S_i=T_i$能构造出来的操作序列。
假设删除$S_i$往 $A$ 里添加(此时$A$有$i-1$个元素),考虑状态转移方程。
考虑两个东西: $dp[l][r]$和$r-l+1=i$
- 如果有$S_i=T_l$ 那么就把 $S_i$放到$[l+1,r]$区间的前面,构成$[l,r]$ 即有$dp[l][r]+=dp[l+1][r]$
- 如果有$S_i=T_r$ 那么就把 $S_i$放到$[l,r-1]$区间的后面,构成$[l,r]$ 即有$dp[l][r]+=dp[l][r-1]$
初始化状态:区间长度为 1 时如果有字符相等那么就会存在$dp[i][i] += dp[i][i-1]$的情况,对于这种情况其实就是单个字符$S_i$在空串基础上前插或后插后成为了符合条件的串之一,实际上应该是$dp[i][i] += 1$,所以我们就预处理一下使$ dp[i][i-1] = 1 $即可。
统计答案:即 统计 A 的前缀部分 $ans=\sum_{i=m}^ndp[1][i]$
Code:
1 | // She is Pretty pretty! |
Description
Solution
Code
EDU59-E. Vasya and Binary String
Description:
给个长度为 $n (n\le100)$ 的 $01$ 串 $s$ ,以及长度为 $n$ 数组 $a$.每次可以选择任意长度 $L$ 的连续子串(要求子串每个字符相同)从原串中去掉,并获得 $a[L]$ 的值。问可能获得的最大值
Solution:
观察数据范围,考虑到用区间 $dp$。
令$dp[ l ][ r ][ k ] $代表的是 $[l, r]$这段区间内,前面有 $k-1$ 个连续的和 $s[l]$ 相同且连续的字符传进来的最大值。
$solve( l, r, k)$ 代表的是处理区间$[L, R]$, 正在处理 $[L, R]$这个区间, 前面有$k-1$个连续的和$s[l]$相同且连续的字符。
考虑转移状态方程:
$dp[l][r][k] = a[k] + solve(l+1,r,1)$。 在 $l$ 这个位置切断连续字符。
$dp[l][r][k] = solve( l+1, i-1, 1) + solve(i, r, k+1)$ 其中 $s[l] == s[i]$ 加入新的连续字符。
Code:
1 | constexpr int N = 201 + 10; |
Beautiful Mirrors
Description
魔镜魔镜我美嘛easy版本,一个人问魔镜他美嘛,魔镜会有$p_i$ %d 概率说他美,他美就会开心,否则不开心,回到第一天,求开心的期望天数。
Solution
概率求期望题目
不妨设 dp[i] 表示第i到 n+1 天期望步数。那么有 dp[n+1] = 0
则有:
求解得到:
推得:
$dp1=\frac{1+p_1+p_1p_2+\cdots p_1p_2\cdots p{n-1}}{p_1p_2\cdots p_n}$
Code
1 | ll dp[maxn], a[maxn], b[maxn]; |
Beautiful Mirrors with queries
Description
在上题的基础上,要求的是回到 $u$ 。
Solution
考虑$[L , R], ans = \frac{1+pl+p_lp{l+1}\cdots +(pl\cdots p_r)}{p_lp{l+1}\cdots p_r}$
对于求这个,考虑:
定义 $s_i=p_ip_2\cdots p_i,t_i=p_1+p_1\cdot p_2+\cdots + p_1 p_2\cdots p_i$
维护前缀积和累和
$ans=\frac{A}{B}, A=\frac{t{r-1}-r{l-2}}{s{l-2}}, B=\frac{s_r}{r{l-1}}$
Code
1 | set<ll> S; |