【题意】
N
N
N 头牛,一开始每头牛左段坐标为
(
x
i
,
y
i
)
(x_i,y_i)
(xi,yi),右段坐标为
(
x
i
+
1
,
y
i
)
(x_i+1,y_i)
(xi+1,yi),拟成一条线段。 开始后,每头牛一直向右跑,花
r
i
r_i
ri 的时间跑完一格。 在原点,有一根向
y
y
y 轴正方向的射线。问你最终有多少头牛能被射线照射到。
【范围】
1
≤
N
≤
5
×
1
0
4
1\le N\le 5\times10^4
1≤N≤5×104
x
i
∈
[
−
1000
,
−
1
]
x_i\in[-1000,-1]
xi∈[−1000,−1]
y
i
∈
[
1
,
1
0
6
]
y_i\in[1,10^6]
yi∈[1,106]
r
i
∈
[
1
,
1
0
6
]
r_i\in[1,10^6]
ri∈[1,106] 保证
y
i
y_i
yi 两两不相同。
【思路】 每头牛触碰
y
y
y 轴的时间计算得到
[
s
i
,
e
i
]
[s_i,e_i]
[si,ei] 我们首先按
y
i
y_i
yi升序。如果
[
s
i
,
e
i
]
[s_i,e_i]
[si,ei] 当中所有时间都被覆盖了,那么这头牛不能被射线射到。反之,可以被射线射到,然后覆盖了这一段的时间。 由于时间很大,我们可以离散化记录,然后使用线段树查询区间最小值和区间覆盖即可。
【题意】 有
N
N
N 个飞机航班,每个飞机航班有一个花费
c
o
s
t
i
cost_i
costi ,还有一条单向的路线
a
1
⋯
a
k
a_1\cdots a_k
a1⋯ak 如果你乘了某个航班,你就只需要花费
c
o
s
t
i
cost_i
costi,不管你之后这个航班坐了几站 。但是你可以在任意位置上机,也可以在任意位置下机。 问你从
A
A
A 到
B
B
B ,最小花费是多少。在最小花费下,最少站点经过数是多少。
【范围】
1
≤
N
≤
1000
1\le N\le 1000
1≤N≤1000
1
≤
c
o
s
t
i
≤
1
0
9
1\le cost_i\le 10^9
1≤costi≤109
1
≤
k
≤
100
1\le k\le 100
1≤k≤100 城市编号
1
≤
x
≤
1000
1\le x \le 1000
1≤x≤1000
【思路】 如果暴力建图,那么点数为
1
0
3
10^3
103,边数为
N
×
k
2
N\times k^2
N×k2,暴力去跑可能可以卡过,但是不优秀。 考虑优化建图。 就像机场一样,我们每一个点可以跑到该站点的车上,站点经过费用为
0
0
0,金钱花费为
c
o
s
t
i
cost_i
costi 在这个站点的车跑到下个站点的车的站点经过费用为
1
1
1,金钱花费为
0
0
0。 在这个站点的车下车到该站点的站点经过费用为
0
0
0,金钱花费为
0
0
0。 这样建图之后,点数为
1
0
3
+
N
k
10^3+Nk
103+Nk,边数为
3
N
k
3Nk
3Nk,再跑最短路就会优秀地多了。
【代码】 时间复杂度:
O
(
E
log
E
)
O(E\log E)
O(ElogE),其中
E
=
3
N
k
E=3Nk
E=3Nk
G
\mathfrak{G}
G Moovie Mooving | 状压
d
p
dp
dp + 二分
【题意】 有
N
N
N 部电影,每部的长度为
D
i
D_i
Di,每部有
C
i
C_i
Ci 次放映的场次,每个放映的场次的开始时间都给定。 问你,从时刻
0
0
0 到时刻
T
T
T,你能否安排看电影的某种次序,首先要求每部电影最多只看一次,其次要求
0
∼
T
0\sim T
0∼T 时刻你都一直在看电影。 对于某一个场次的电影, 只要在放映时间内,你可以选择中途开始看,或者中途就离开。 问你,满足前面的要求下,你选择的电影场次最少是多少?
【范围】
1
≤
N
≤
20
1\le N\le 20
1≤N≤20
1
≤
D
i
≤
T
≤
1
0
9
1\le D_i\le T\le 10^9
1≤Di≤T≤109
1
≤
C
i
≤
1
0
3
1\le C_i\le 10^3
1≤Ci≤103
【思路】
N
=
20
N=20
N=20,基本上就是状压了。我们设
d
p
[
S
]
dp[S]
dp[S] 表示看了状态(集合)
S
S
S 的电影后,能一直看电影的最长长度。 考虑到状态转移,我们假设
2
j
&
i
≠
0
2^j\&i\ne 0
2j&i=0,也就是说可以从状态
i
−
2
j
i-2^j
i−2j 推到状态
i
i
i 我们已经获得了
d
p
[
i
−
2
j
]
dp[i-2^j]
dp[i−2j] 的值了,接下来需要看第
j
j
j 部电影。我们从什么时候开始看是最优的呢?就是从所有能看的场次里,选择看完出来最晚的那一场。由于电影长度是固定的,所以我们使用
u
p
p
e
r
_
b
o
u
n
d
upper\_bound
upper_bound 函数快速算出那场即可。
【代码】 时间复杂度:
O
(
2
n
×
log
1
0
3
)
O(2^n\times \log 10^3)
O(2n×log103)
J
\mathfrak{J}
J Palindromic Paths II |
d
p
dp
dp + 滚动数组优化
【题意】
N
×
N
N\times N
N×N 的字母矩阵,求从
(
1
,
1
)
(1,1)
(1,1),每步可以向下或者向右一个单位,走到终点
(
N
,
N
)
(N,N)
(N,N) 的字符串为回文串的路径个数
【范围】
1
≤
N
≤
500
1\le N\le 500
1≤N≤500
【思路】 我们需要起点
(
1
,
1
)
(1,1)
(1,1),每步向右/下走到对角线,然后终点
(
n
,
n
)
(n,n)
(n,n),每步向左/上走到对角线。 我们设
d
p
[
i
]
[
j
]
[
k
]
[
p
]
dp[i][j][k][p]
dp[i][j][k][p] 表示起点走到
(
i
,
j
)
(i,j)
(i,j),终点走到
(
k
,
p
)
(k,p)
(k,p) 时候的合法路径数量。 由于是四维,时间复杂度至少为
O
(
N
4
)
O(N^4)
O(N4),显然不行。 考虑到,起点走
x
x
x 步,终点也是走
x
x
x 步。所以我们有
(
i
−
1
)
+
(
j
−
1
)
=
(
n
−
k
)
+
(
n
−
p
)
(i-1)+(j-1)=(n-k)+(n-p)
(i−1)+(j−1)=(n−k)+(n−p) 所以我们得到了:
p
=
2
n
+
2
−
k
−
i
−
j
p=2n+2-k-i-j
p=2n+2−k−i−j,于是我们的
d
p
dp
dp可以省略一维,变成
d
p
[
i
]
[
j
]
[
k
]
dp[i][j][k]
dp[i][j][k] 考虑到状态转移。
(
i
,
j
)
(i,j)
(i,j) 下一步走到
(
i
i
,
j
j
)
(ii,jj)
(ii,jj) 有两种方案,
(
k
,
p
)
(k,p)
(k,p) 下一步走到
(
k
k
,
p
p
)
(kk,pp)
(kk,pp) 也有两种方案。 我们枚举这四种方案,状态转移方程就变成了
d
p
[
i
i
]
[
j
j
]
[
k
k
]
=
+
d
p
[
i
]
[
j
]
[
k
]
,
满
足
a
a
[
i
i
]
[
j
j
]
=
a
a
[
k
k
]
[
p
p
]
dp[ii][jj][kk]\overset{+}{=}dp[i][j][k],满足aa[ii][jj]=aa[kk][pp]
dp[ii][jj][kk]=+dp[i][j][k],满足aa[ii][jj]=aa[kk][pp] 最终答案即为
∑
i
d
p
[
i
i
]
[
i
i
]
[
i
i
]
\sum_idp[ii][ii][ii]
∑idp[ii][ii][ii] 但是这样会
M
L
E
\color{red}MLE
MLE,我们考虑还要优化。按照滚动数组进行优化。 因为每次算完
d
p
[
i
]
[
j
]
[
k
]
dp[i][j][k]
dp[i][j][k],算完所有的
i
i
i,接下来的
d
p
[
i
+
1
]
[
j
]
[
k
]
dp[i+1][j][k]
dp[i+1][j][k] 以至于后面的
i
i
i 都不需要这些没有用的状态了。 于是我们可以第一维滚动一下,让空间复杂度变为
O
(
N
2
)
O(N^2)
O(N2) 我这里有两种优化方案。就是时间和空间的权衡方案了。
【优化方案一】
T
i
m
e
(
M
s
)
:
1906
/
2000
Time(Ms):1906/2000
Time(Ms):1906/2000
M
e
m
o
(
K
b
)
:
6710
Memo(Kb):6710
Memo(Kb):6710 时间复杂度:
O
(
5
N
3
)
O(5N^3)
O(5N3) 空间复杂度:
O
(
4
N
2
)
O(4N^2)
O(4N2)
/*
_ __ __ _ _
| | \ \ / / | | (_)
| |__ _ _ \ V /__ _ _ __ | | ___ _
| '_ \| | | | \ // _` | '_ \| | / _ \ |
| |_) | |_| | | | (_| | | | | |___| __/ |
|_.__/ \__, | \_/\__,_|_| |_\_____/\___|_|
__/ |
|___/
*/int n;char aa[MAX][MAX];
ll dp[2][MAX][MAX];
ll dp2[MAX][MAX];intmain(){scanf("%d",&n);for(int i =1;i <= n;++i)scanf("%s",aa[i]+1);if(aa[1][1]!= aa[n][n]){puts("0");return0;}
ll res =0;
dp[1][1][n]=1;for(int i =1;i <= n;++i){for(int j =1;j <= n;++j){for(int k =1;k <= n;++k){
dp[0][j][k]=(dp2[j][k]+ dp[1][j][k])% MOD;
dp[1][j][k]=0;
dp2[j][k]=0;}if(i + j >= n +1)break;for(int k = n;k >=1;--k){int l =2* n +2- i - j - k;if(l <1|| l > n)continue;if(aa[i][j]!= aa[k][l])continue;if(dp[0][j][k]==0)continue;for(int d1 =0;d1 <2;++d1)for(int d2 =0;d2 <2;++d2){int ii,jj,kk,pp;if(d1 ==0){
ii = i +1;
jj = j;}else{
ii = i;
jj = j +1;}if(d2 ==0){
kk = k -1;
pp = l;}else{
kk = k;
pp = l -1;}if(aa[ii][jj]== aa[kk][pp]){if(ii == kk){
dp[1][jj][kk]=(dp[1][jj][kk]+ dp[0][j][k])% MOD;}else{
dp2[jj][kk]=(dp2[jj][kk]+ dp[0][j][k])% MOD;}if(ii == kk && jj == pp){
res =(res + dp[0][j][k])% MOD;}}}}}}printf("%lld",res);return0;}
【优化方案二】
T
i
m
e
(
M
s
)
:
1953
/
2000
Time(Ms):1953/2000
Time(Ms):1953/2000
M
e
m
o
(
K
b
)
:
2398
Memo(Kb):2398
Memo(Kb):2398 时间复杂度:
O
(
6
N
3
)
O(6N^3)
O(6N3) 空间复杂度:
O
(
3
N
2
)
O(3N^2)
O(3N2) 这里开
l
l
ll
ll 就过不了了,得开
i
n
t
int
int
/*
_ __ __ _ _
| | \ \ / / | | (_)
| |__ _ _ \ V /__ _ _ __ | | ___ _
| '_ \| | | | \ // _` | '_ \| | / _ \ |
| |_) | |_| | | | (_| | | | | |___| __/ |
|_.__/ \__, | \_/\__,_|_| |_\_____/\___|_|
__/ |
|___/
*/int n;char aa[MAX][MAX];int dp[2][MAX][MAX];int dp2[MAX];intmain(){scanf("%d",&n);for(int i =1;i <= n;++i)scanf("%s",aa[i]+1);if(aa[1][1]!= aa[n][n]){puts("0");return0;}int res =0;
dp[1][1][n]=1;for(int i =1;i <= n;++i){for(int j =1;j <= n;++j)for(int k =1;k <= n;++k){
dp[0][j][k]= dp[1][j][k];
dp[1][j][k]=0;}for(int j =1;j <= n;++j){for(int k = n;k >=1;--k){
dp[0][j][k]=((ll)dp[0][j][k]+ dp2[k])% MOD;
dp2[k]=0;}if(i + j >= n +1)break;for(int k = n;k >=1;--k){int l =2* n +2- i - j - k;if(l <1)break;if(aa[i][j]!= aa[k][l])continue;if(dp[0][j][k]==0)continue;for(int d1 =0;d1 <2;++d1)for(int d2 =0;d2 <2;++d2){int ii,jj,kk,pp;if(d1 ==0){
ii = i +1;
jj = j;}else{
ii = i;
jj = j +1;}if(d2 ==0){
kk = k -1;
pp = l;}else{
kk = k;
pp = l -1;}if(aa[ii][jj]== aa[kk][pp]){if(i == ii){
dp2[kk]=((ll)dp2[kk]+ dp[0][j][k])% MOD;}else{
dp[1][jj][kk]=((ll)dp[1][jj][kk]+ dp[0][j][k])% MOD;}if(ii == kk && jj == pp){
res =((ll)res + dp[0][j][k])% MOD;}}}}}}printf("%d",res);return0;}