Fork me on GitHub

ZROI#1012

ZROI#1012

ZROI#1012

考虑如果没有 $backspace$ 操作,那就是个 $SB$ 递推.

考虑加入 $backspce$ 后有什么影响,那就是出现环状转移.

那咋办,显然所有的转移一定都是正权,也就是不会有一种转移,使状态变化的同时减少答案次数.

我们知道,平时 $DP$ 的转移就是一张边带权的 $DAG$ , 我们要求的答案其实就是这张 $DAG$ 上从起始点到目标点的最短/长路.

那么这个题,我们不如就把这样一张转移图建出来,直接采用 $SPFA$ 的方式以重复入队来完成转移,因为一定会有一些状态是不在环中的,所以环上的状态可以通过多次入队调整松弛完成最优化.

建边的时候要考虑全面,漏掉一种边很可能就会收获 $0pts$ 的好成绩.

$backspace$ 操作肯定不会有很多,所以边数并不巨大,理论上需要 $n\times log_2{n}$ 条,而实际只需要向后 $\times 5$ 就能 $AC$.(多了会 $TLE$)

当然,可能某些人的代码需要卡卡常.

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC target("sse,sse2,sse3,sse4.1,sse4.2,popcnt,abm,mmx,avx")
#pragma comment(linker,"/STACK:102400000,102400000")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
#include <cmath>
#include <ctime>
#include <map>
#include <set>
#define MEM(x,y) memset ( x , y , sizeof ( x ) )
#define rep(i,a,b) for (int i = (a) ; i <= (b) ; ++ i)
#define per(i,a,b) for (int i = (a) ; i >= (b) ; -- i)
#define pii pair < int , int >
#define one first
#define two second
#define rint read<int>
#define pb push_back
#define db double
#define ull unsigned long long
#define lowbit(x) ( x & ( - x ) )

using std::queue ;
using std::set ;
using std::pair ;
using std::max ;
using std::min ;
using std::priority_queue ;
using std::vector ;
using std::swap ;
using std::sort ;
using std::unique ;
using std::greater ;

template < class T >
inline T read () {
T x = 0 , f = 1 ; char ch = getchar () ;
while ( ch < '0' || ch > '9' ) {
if ( ch == '-' ) f = - 1 ;
ch = getchar () ;
}
while ( ch >= '0' && ch <= '9' ) {
x = ( x << 3 ) + ( x << 1 ) + ( ch - 48 ) ;
ch = getchar () ;
}
return f * x ;
}

const int N = 1e7 + 100 ;
const int inf = 0x7f7f7f7f ;
struct edge { int to , next , data ; } e[N<<1] ;

queue < int > q ;
int n , x , dis[N] , head[N] , tot , maxn = - inf ;
bool vis[N] ;

inline void build (int u , int v , int w) {
e[++tot].next = head[u] ; e[tot].to = v ;
e[tot].data = w ; head[u] = tot ; return;
}

inline void SPFA (int cur) {
MEM ( dis , 0x7f ) ; MEM ( vis , 0 ) ;
q.push ( cur ) ; vis[cur] = true ; dis[cur] = 0 ;
while ( ! q.empty () ) {
int j = q.front () ; q.pop () ; vis[j] = false ;
for (int i = head[j] ; i ; i = e[i].next) {
int k = e[i].to ;
if ( dis[k] > dis[j] + e[i].data ) {
dis[k] = dis[j] + e[i].data ;
if ( ! vis[k] ) q.push ( k ) , vis[k] = true ;
}
}
}
return ;
}

signed main (int argc , char * argv[]) {
x = rint () ; n = rint () ; maxn = max ( n , x ) + 1 ;
rep ( i , 0 , maxn ) {
build ( i , i + 1 , 1 ) ;
build ( i , i - 1 , 1 ) ;
build ( i , 0 , 3 ) ;
}
rep ( i , 1 , maxn )
for (int j = 1 ; j <= 5 && i * j <= maxn ; ++ j)
build ( i , i * j , 4 + 2 * ( j - 1 ) ) ;
SPFA ( x ) ; printf ("%lld\n" , dis[n] ) ;
return 0 ;
}