Codeforces Round #703 (Div. 2) 题解
文章目錄
- A. Shifting Stacks
- B. Eastern Exhibition
- C. Guessing the Greatest
- D. Max Median
- E. Paired Payment
- F. Pairs of Paths
#703 (Div. 2)
A. Shifting Stacks
從左往右構造遞增0,1,2...,如果這樣都不能遞增就肯定無解
雷區:不能用等差數列算個數,因為這個移動必須是左到右的不能逆,hack: 0 0 3 AC:NO WA:YES
B. Eastern Exhibition
以前考試遇到過的相似度百分之九十五,橫縱坐標拆開分別取中位數即可;偶數個點中位數是一段區間
#include <cstdio> #include <algorithm> using namespace std; #define int long long #define maxn 1005 int T, n; int x[maxn], y[maxn];signed main() {scanf( "%lld", &T );while( T -- ) {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ )scanf( "%lld %lld", &x[i], &y[i] );sort( x + 1, x + n + 1 );sort( y + 1, y + n + 1 );if( n & 1 ) printf( "1\n" );else {int l = n >> 1, r = l + 1;printf( "%lld\n", ( x[r] - x[l] + 1 ) * ( y[r] - y[l] + 1 ) );}}return 0; }C. Guessing the Greatest
第一次詢問整個序列確定次大值,然后再一次詢問判斷最大值是在左邊還是右邊
之后就是二分位置與次大值進行詢問,找到最大值
煞筆二分再次死亡
#include <cstdio> int n;int print( int l, int r ) {if( l >= r ) return -1;printf( "? %d %d\n", l, r );fflush( stdout );int pos;scanf( "%d", &pos );return pos; }int main() {scanf( "%d", &n );int pos = print( 1, n );if( pos > 1 && print( 1, pos ) == pos ) {int l = 1, r = pos;while( l < r ) {int mid = ( l + r + 1 ) >> 1;if( print( mid, pos ) == pos ) l = mid;else r = mid - 1;}printf( "! %d\n", l );fflush( stdout );}else {int l = pos, r = n;while( l < r ) {int mid = ( l + r ) >> 1;if( print( pos, mid ) == pos ) r = mid;else l = mid + 1;}printf( "! %d\n", l );fflush( stdout );}return 0; }D. Max Median
二分最后的答案,將原數組轉換為大于等于為111,小于為?1-1?1,看有無一段長度大于等于kkk的區間和為正
對于第iii個位置,有0,1,2,...,i?k0,1,2,...,i-k0,1,2,...,i?k種選擇,用前綴和最小值優化即可做到O(nlogn)O(nlogn)O(nlogn)
#include <cstdio> #include <iostream> using namespace std; #define maxn 200005 int n, k, ans; int a[maxn], b[maxn], minn[maxn];bool check( int x ) {for( int i = 1;i <= n;i ++ )if( a[i] >= x ) b[i] = 1;else b[i] = -1;for( int i = 1;i <= n;i ++ )b[i] += b[i - 1];for( int i = 1;i <= n;i ++ )minn[i] = min( minn[i - 1], b[i] );for( int i = k;i <= n;i ++ )if( b[i] > minn[i - k] ) return 1;return 0; }int main() {scanf( "%d %d", &n, &k );for( int i = 1;i <= n;i ++ )scanf( "%d", &a[i] );int l = 1, r = n;while( l <= r ) {int mid = ( l + r ) >> 1;if( check( mid ) ) ans = mid, l = mid + 1;else r = mid - 1;}printf( "%d\n", ans );return 0; }E. Paired Payment
如果可以一條一條邊地走,就是一個dijkstra板子
但必須兩條兩條走,也就是說這一次走的邊產生的貢獻與上一條邊邊權掛鉤
再觀察邊權范圍,只有505050,小得離譜;很有可能就是從這里入手
不妨把上一條邊權是多少帶著dijkstra
設disi,jdis_{i,j}disi,j?表示走到iii點上一條的邊權為jjj的最短路
最后為什么是disi,0dis_{i,0}disi,0?,這是為了dijkstra的正確性,disi,0dis_{i,0}disi,0?含義比較特殊,表示iii為結束點(第二條邊的入點)
#include <queue> #include <cstdio> #include <vector> #include <cstring> using namespace std; #define int long long #define maxn 200005 struct node {int u, lst, d;node(){}node( int U, int Lst, int D ) {u = U, lst = Lst, d = D;}bool operator < ( node t ) const {return d > t.d;} }; int n, m; priority_queue < node > q; vector < pair < int, int > > G[maxn]; int dis[maxn][55];signed main() {scanf( "%lld %lld", &n, &m );for( int i = 1, u, v, w;i <= m;i ++ ) {scanf( "%lld %lld %lld", &u, &v, &w );G[u].push_back( make_pair( v, w ) );G[v].push_back( make_pair( u, w ) );}memset( dis, 0x3f, sizeof( dis ) );dis[1][0] = 0;q.push( node( 1, 0, 0 ) );while( ! q.empty() ) {node t = q.top(); q.pop();int u = t.u, lst = t.lst;if( dis[u][lst] < t.d ) continue;for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i].first, w = G[u][i].second;int nxt = lst ? 0 : w;if( dis[v][nxt] > dis[u][lst] + 2 * lst * w + w * w )q.push( node( v, nxt, dis[v][nxt] = dis[u][lst] + 2 * lst * w + w * w ) );}}for( int i = 1;i <= n;i ++ )if( dis[i][0] >= 0x3f3f3f3f ) printf( "-1 " );else printf( "%lld ", dis[i][0] );return 0; }F. Pairs of Paths
事實上,只有兩種情況
case 1: 兩條路徑相交于一條路徑的lcalcalca
case 2: 兩條路徑擁有公共的lcalcalca
這意味著,符合條件的答案一定是交于某個lcalcalca的
對于每一條路徑都定義一個三元組(a,b,lca)(a,b,lca)(a,b,lca),其中a,ba,ba,b分別表示兩個端點的樹根,如果端點是lcalcalca,那么重新給個編號(因為這時候要判定為不同)
case1: 按lcalcalca排序,aaa嚴格遞減排序后,用桶存儲之前信息,然后每次加S?cntbS-cnt_bS?cntb?,然后再把cnta++,cntb++cnt_a++,cnt_b++cnta?++,cntb?++
case2: 另一個lcalcalca一定是這個交點lcalcalca的祖先,用樹狀數組記錄
#include <cstdio> #include <vector> #include <iostream> #include <algorithm> using namespace std; #define maxn 600005 #define int long long struct node{int u, v, tu, tv, lca; }MS[maxn]; vector < int > G[maxn]; int n, m, T, cnt; int dep[maxn], l[maxn], r[maxn], tree[maxn], tot[maxn]; int f[maxn][20];bool cmp( node x, node y ) {if( dep[x.lca] == dep[y.lca] )if( x.lca == y.lca ) return x.tu > y.tu;else return x.lca < y.lca;elsereturn dep[x.lca] < dep[y.lca]; }void dfs( int u, int fa ) {dep[u] = dep[fa] + 1, f[u][0] = fa;for( int i = 1;i < 20;i ++ )f[u][i] = f[f[u][i - 1]][i - 1];l[u] = ++ cnt;for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == fa ) continue;else dfs( v, u );}r[u] = cnt; }int lca( int u, int v ) {if( dep[u] < dep[v] ) swap( u, v );for( int i = 19;~ i;i -- )if( dep[f[u][i]] >= dep[v] )u = f[u][i];if( u == v ) return u;for( int i = 19;~ i;i -- )if( f[u][i] != f[v][i] )u = f[u][i], v = f[v][i];return f[u][0]; }int get_top( int u, int lca ) {if( u == lca ) return ++ T;for( int i = 19;~ i;i -- )if( dep[f[u][i]] > dep[lca] )u = f[u][i];return u; }int lowbit( int x ) {return x & ( -x ); }void add( int x ) {for( int i = x;i <= n;i += lowbit( i ) )tree[i] ++; }int ask( int x ) {int ans = 0;for( int i = x;i;i -= lowbit( i ) )ans += tree[i];return ans; }signed main() {scanf( "%lld", &n ); T = n;for( int i = 1, u, v;i < n;i ++ ) {scanf( "%lld %lld", &u, &v );G[u].push_back( v );G[v].push_back( u );}dfs( 1, 0 );scanf( "%lld", &m );for( int i = 1;i <= m;i ++ ) {scanf( "%lld %lld", &MS[i].u, &MS[i].v );MS[i].lca = lca( MS[i].u, MS[i].v );MS[i].tu = get_top( MS[i].u, MS[i].lca );MS[i].tv = get_top( MS[i].v, MS[i].lca );if( MS[i].tu > MS[i].tv ) {swap( MS[i].tu, MS[i].tv );swap( MS[i].u, MS[i].v );}}sort( MS + 1, MS + m + 1, cmp );int ans = 0;for( int i = 1, j;i <= m;i = j + 1 ) { j = i;while( j < m && MS[j + 1].lca == MS[i].lca ) j ++;cnt = 0;for( int s = i, t;s <= j;s = t + 1 ) {t = s;while( t < j && MS[t + 1].tu == MS[s].tu ) t ++;for( int k = s;k <= t;k ++ )ans += cnt - tot[MS[k].tv];for( int k = s;k <= t;k ++ )tot[MS[k].tv] ++, tot[MS[k].tu] ++;cnt += ( t - s + 1 );}for( int k = i;k <= j;k ++ )tot[MS[k].tu] = tot[MS[k].tv] = 0;for( int k = i;k <= j;k ++ ) {ans += ask( r[MS[k].lca] ) - ask( l[MS[k].lca] - 1 );if( MS[k].tu <= n ) ans -= ask( r[MS[k].tu] ) - ask( l[MS[k].tu] - 1 );if( MS[k].tv <= n )ans -= ask( r[MS[k].tv] ) - ask( l[MS[k].tv] - 1 );} for( int k = i;k <= j;k ++ )add( l[MS[k].u] ), add( l[MS[k].v] );}printf( "%lld\n", ans );return 0; }總結
以上是生活随笔為你收集整理的Codeforces Round #703 (Div. 2) 题解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在异地就医后才备案吗(在异地就医后才备案
- 下一篇: Codeforces Round #70