Codeforces Round #809 (Div. 2)
很自然想到,枚举数组取
t = m i n ( a [ i ] , m + 1 − a [ i ] ) t = min( a[i] , m+1 -a[i] ) t = m i n ( a [ i ] , m + 1 − a [ i ] )
k = m a x ( a [ i ] , m + 1 − a [ i ] ) k = max(a[i],m+1-a[i]) k = m a x ( a [ i ] , m + 1 − a [ i ] )
若 s [ t ] s[t] s [ t ] 不为 A A A , 变为 A A A 并标记
s [ t ] s[t] s [ t ] 被标记,则把s [ k ] s[k] s [ k ] 变为 A A A 并标记
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 void solve () { int n,m; cin>>n>>m; vector<int > a (n+1 ) ; forr(i,1 ,n) cin >> a[i]; string s; forr(i,1 ,m) s+="B" ; map<int ,int > mp; forr(i,1 ,n){ int t = min (a[i],m+1 -a[i]); int k = max (a[i],m+1 -a[i]); if (mp[t-1 ]){ s[k-1 ] = 'A' ; mp[k-1 ]++; } else { mp[t-1 ]++; s[t-1 ] = 'A' ; } } cout << s << endl; }
找规律
对于数 i i i , 当数 i i i 之间间隔为偶数
时 ,a n s [ i ] + + ans[i]++ a n s [ i ] + + ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 vector<int > g[100005 ]; void solve () { int n;cin>>n; vector<int > a (n+1 ) ; set<int > s; forr(i,1 ,n) cin >> a[i],g[a[i]].push_back (i),s.insert (a[i]); map<int ,int > mp; for (auto it = s.begin ();it!=s.end ();it++){ int t = *it; mp[t] = 1 ; for (int i = 1 ;i < g[t].size ();i++){ int tt = g[t][i] - g[t][i-1 ] - 1 ; if ( (tt%2 )==0 ) mp[t]++; } } forr(i,1 ,n) cout << mp[i] <<" \n" [i==n]; for (auto it = s.begin ();it!=s.end ();it++) g[*it].clear (); }
先要求峰最多
再要求添加最少
奇数答案一定隔一个判断一次,贡献一次答案
考虑偶数
偶数在满足峰最多的前提,有一次可以
隔两个选并且只有
一个位置,否则不可能取到最多峰
那么枚举哪个位置隔二个,很多题解都是通过两个前缀来做
官方 tutorial 方法更容易理解
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 int a[100005 ];int cal (int x) { return max (0ll ,(max (a[x-1 ],a[x+1 ])+1 -a[x])); } void solve () { int n; cin >> n; forr(i,1 ,n) cin >> a[i]; int res = 0 ; if (n&1 ){ for (int i = 2 ;i <= n;i+=2 ){ if (a[i] > a[i-1 ] && a[i] > a[i+1 ]) continue ; else { res += max (a[i-1 ],a[i+1 ]) + 1 -a[i]; } } cout << res << endl; } else { for (int i = 2 ; i < n;i+=2 ){ if (a[i] > a[i-1 ] && a[i] > a[i+1 ]) continue ; else { res += max (a[i-1 ],a[i+1 ]) + 1 -a[i]; } } int sum = res; for (int i = n-1 ;i>1 ;i-=2 ){ res -= cal (i-1 ); res += cal (i); sum = min (res,sum); } cout << sum << endl; } }
$n <= 3000 $
考虑 min 1 < = i < = n ( ⌊ a i p i ⌋ ) = v \min\limits_{1<=i<=n}(\lfloor \frac{a_i}{p_i} \rfloor) \ = \ v 1 < = i < = n min ( ⌊ p i a i ⌋ ) = v
分析可知 v ∈ [ 0 , a 1 ] v ∈ [0,a_1] v ∈ [ 0 , a 1 ]
反证
若 v ∈ [ a 2 , a n ] v ∈ [a_2,a_n] v ∈ [ a 2 , a n ] 因为 min 1 < = i < = n ( ⌊ a i p i ⌋ ) = v \min\limits_{1<=i<=n}(\lfloor \frac{a_i}{p_i} \rfloor) \ = \ v 1 < = i < = n min ( ⌊ p i a i ⌋ ) = v , 那么对于 x = [ a 1 , v − 1 ] x \ =\ [a_1,v-1] x = [ a 1 , v − 1 ] , 总有 x p i < v \frac{x}{p_i} < v p i x < v
故 v ∈ [ 0 , a 1 ] v ∈ [0,a_1] v ∈ [ 0 , a 1 ]
那么枚举 v v v , 计算出 p i = m i n ( k , a i / v ) p_i = min(k,a_i/v) p i = m i n ( k , a i / v ) ,再用计算出的 p i p_i p i 求出 max 1 < = i < = n ( ⌊ a i p i ⌋ ) \max\limits_{1<=i<=n}(\lfloor \frac{a_i}{p_i} \rfloor) 1 < = i < = n max ( ⌊ p i a i ⌋ ) 和 min 1 < = i < = n ( ⌊ a i p i ⌋ ) \min\limits_{1<=i<=n}(\lfloor \frac{a_i}{p_i} \rfloor) 1 < = i < = n min ( ⌊ p i a i ⌋ )
做差求最大的差值 r e s res r e s
O ( n ∗ a i ) O(n*a_i) O ( n ∗ a i )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 void solve () { int n,k; cin>>n>>k; vector<int > a (n+1 ) ; forr(i,1 ,n) cin >> a[i]; int mx = -inf,mi = inf; int res = inf; for (int v = 0 ;v <= a[1 ];v++){ int p; forr(i,1 ,n){ if (!v) p = k; else p = min (k,a[i]/v); mx = max (mx,a[i]/p); mi = min (mi,a[i]/p); } res = min (res,mx-mi); mx = -inf,mi = inf; } cout << res << endl; }
Kruskal 重构树
给一个区间[ l , r ] [l,r] [ l , r ]
要求的就是这个区间的子区间 ( [ a , b ] l < = a < = b < = r [a,b]\,\ l<=a<=b<=r [ a , b ] l < = a < = b < = r a → b a\rightarrow b a → b 的所有路径最长边权的最小值
)的最大值
[ a , b ] l < = a < = b < = r [a,b]\,\ l<=a<=b<=r [ a , b ] l < = a < = b < = r a → b a\rightarrow b a → b 的所有路径最长边权的最小值
,可以用Kruskal重构树
直接求出
然后就是对 [l,r] 的一次区间求和, 因为是静态的可使用 $ ST表 $ O ( n ) O(n) O ( n ) 预处理
注意各种数组的初始化
问题
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 int n, m, q;struct node { int u, v, w; bool operator <(const node &t) const { return w < t.w; } } edge[400005 ]; struct nod { int to, ne; } e[400005 <<1 ]; int h[400005 <<1 ], cnt = 1 ;void add (int u, int v) { e[++cnt] = {v, h[u]}; h[u] = cnt; } int pre[400005 <<1 ];int tot;int val[400005 ];int d[400005 <<1 ];int f[200005 ][21 ]; int find (int x) { return x == pre[x] ? x : pre[x] = find (pre[x]); } void dfs (int u, int fa) { d[u] = d[fa] + 1 ; for (int i = h[u]; i; i = e[i].ne) { int v = e[i].to; if (v == fa) continue ; f[v][0 ] = u; forr(k, 1 , 20 ) if (f[v][k - 1 ]) f[v][k] = f[f[v][k - 1 ]][k - 1 ]; else break ; dfs (v, u); } } int lca (int a, int b) { if (d[a] > d[b]) swap (a, b); for (int i = 20 ; i >= 0 ; i--) if (d[f[b][i]] >= d[a]) b = f[b][i]; if (a == b) return a; for (int i = 20 ; i >= 0 ; i--) if (f[a][i] != f[b][i]) a = f[a][i], b = f[b][i]; return f[a][0 ]; } void kruskal () { sort (edge + 1 , edge + 1 + m); forr(i, 1 , n) pre[i] = i,d[i] = 0 ; tot = n; forr(i, 1 , m) { int a = find (edge[i].u), b = find (edge[i].v); if (a != b) { val[++tot] = edge[i].w; d[tot] = 0 ; pre[tot] = pre[a] = pre[b] = tot; add (tot, a); add (a, tot); add (b, tot); add (tot, b); } } for (int i = tot; i >= 1 ; i--) { if (!d[i]){ dfs (i, -1 ); } } } int dis[200005 ];int ff[200005 ][21 ];void ST () { forr(i,1 ,n-1 ) ff[i][0 ] = dis[i]; forr(i,1 ,20 )for (int j = 1 ;j+(1 <<i)-1 <= n-1 ;j++){ ff[j][i] = max (ff[j][i-1 ],ff[j+(1 <<(i-1 ))][i-1 ]); } } int query (int l,int r) { int s = __lg(r-l+1 ); return max (ff[l][s],ff[r-(1 <<s)+1 ][s]); } void solve () { cin >> n >> m >> q; cnt = 1 ; forr(i,1 ,2 *n) h[i] = 0 ; forr(i,1 ,2 *n) forr(j,1 ,20 ) f[i][j] = 0 ; cnt = 1 ; forr(i, 1 , m) { int u, v; cin >> u >> v; edge[i] = {u, v, i}; } kruskal (); for (int i = 1 ;i<n;i++){ int t = lca (i,i+1 ); dis[i] = val[t]; } ST (); while (q--) { int l, r; cin >> l >> r; if (l==r) cout << 0 <<" " ; else cout << query (l,r-1 ) << " " ; } cout << endl; }