日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Codeforces Round #740 (Div. 2, based on VK Cup 2021 - Final (Engine)) A-F全题解

發(fā)布時間:2023/12/3 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Codeforces Round #740 (Div. 2, based on VK Cup 2021 - Final (Engine)) A-F全题解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Codeforces Round #740 (Div. 2, based on VK Cup 2021 - Final (Engine))

文章目錄

  • A. Simply Strange Sort
  • B. Charmed by the Game
  • C. Deep Down Below
  • D1/D2. Up the Strip
  • E. Bottom-Tier Reversals
  • F. Top-Notch Insertions

A. Simply Strange Sort

簽到題,暴力做

#include <cstdio> #include <iostream> using namespace std; #define maxn 1000 int n, T; int a[maxn];int main() {scanf( "%d", &T );while( T -- ) {scanf( "%d", &n );for( int i = 1;i <= n;i ++ ) scanf( "%d", &a[i] );int ans = 0;for( int i = 1;i;i ++ ) {for( int j = ( i & 1 ? 1 : 2 );j < n;j += 2 )if( a[j] > a[j + 1] ) swap( a[j], a[j + 1] ), ans = i;bool flag = 1;for( int j = 1;j < n;j ++ )if( a[j] > a[j + 1] ) {flag = 0;break;}if( flag ) break;}printf( "%d\n", ans );}return 0; }

B. Charmed by the Game

簡單題

分總場數(shù)n=a+bn=a+bn=a+b的奇偶討論,假設(shè)以Alice Bob第一場發(fā)球

算出每個人發(fā)球的場數(shù),計算出某個勝場不夠的人至少要break多少場

之后只能兩人相互break相同場數(shù)才能保持彼此贏的場數(shù)滿足a/b

用vis[i]記錄break恰好iii場是否可以,每次都是+2+2+2暴力加

碰到已經(jīng)打過標(biāo)記的就可以跳出循環(huán)

#include <cstdio> #define maxn 200005 int ans; bool vis[maxn];int main() {int T, a, b, n, ta, tb;scanf( "%d", &T );while( T -- ) {scanf( "%d %d", &a, &b );n = a + b, ans = 0;for( int i = 0;i <= n;i ++ ) vis[i] = 0;if( n & 1 ) {ta = ( n + 1 ) >> 1, tb = n >> 1;if( ta < a )for( int i = a - ta;i <= a - ta + 2 * b;i += 2 )if( ! vis[i] ) vis[i] = 1; else break;elsefor( int i = b - tb;i <= b - tb + 2 * a;i += 2 )if( ! vis[i] ) vis[i] = 1; else break;ta = n >> 1, tb = ( n + 1 ) >> 1;if( ta < a )for( int i = a - ta;i <= a - ta + 2 * b;i += 2 )if( ! vis[i] ) vis[i] = 1; else break;elsefor( int i = b - tb;i <= b - tb + 2 * a;i += 2 )if( ! vis[i] ) vis[i] = 1; else break;}else {ta = tb = n >> 1;if( ta < a )for( int i = a - ta;i <= a - ta + 2 * b;i += 2 )if( ! vis[i] ) vis[i] = 1; else break;elsefor( int i = b - tb;i <= b - tb + 2 * a;i += 2 )if( ! vis[i] ) vis[i] = 1; else break;}for( int i = 0;i <= n;i ++ ) ans += vis[i];printf( "%d\n", ans );for( int i = 0;i <= n;i ++ ) if( vis[i] ) printf( "%d ", i );printf( "\n" );}return 0; }

C. Deep Down Below

簡單題

貪心

考慮要通過一個洞穴,初始帶的力量值最小是多少

顯然為max?{armori+1?(i?1)}\max\Big\{armor_i+1-(i-1)\Big\}max{armori?+1?(i?1)}

在第iii個怪物前面可以有i?1i-1i?1個怪物殺死獲得提升的機會,然后要求嚴(yán)格大于怪物生命值,所以+1+1+1

將這個值定義為洞穴的通關(guān)要求,升序排列洞穴

每次通過一個洞穴力量值就會增加洞穴的怪物數(shù)那么大

在下一個洞穴前判斷能否通過,不能就加上差的力量值

#include <cstdio> #include <algorithm> using namespace std; #define int long long #define maxn 100005 struct node { int id, val, k; }armor[maxn]; int T, n;signed main() {scanf( "%lld", &T );while( T -- ) {scanf( "%lld", &n );for( int i = 1, x;i <= n;i ++ ) {armor[i].id = i, armor[i].val = 0;scanf( "%lld", &armor[i].k );for( int j = 1;j <= armor[i].k;j ++ ) {scanf( "%lld", &x );armor[i].val = max( armor[i].val, x + 1 - ( j - 1 ) );}}sort( armor + 1, armor + n + 1, []( node x, node y ) { return x.val < y.val; } );int ans = armor[1].val, now = armor[1].val;for( int i = 1;i <= n;i ++ )if( now >= armor[i].val ) now += armor[i].k;else ans += armor[i].val - now, now = armor[i].val + armor[i].k;printf( "%lld\n", ans );}return 0; }

D1/D2. Up the Strip

簡單DPDPDP

設(shè)計fi:f_i:fi?: 移動到格子iii的方案數(shù),由n→1n\rightarrow 1n1轉(zhuǎn)移

  • iii后面的每個格子都可以通過?x-x?x的操作轉(zhuǎn)移過來

    fi+=∑j=i+1nfjf_i+=\sum_{j=i+1}^nf_jfi?+=j=i+1n?fj?

  • iii后面的格子(以2?i2*i2?i開始)都可以通過/x/x/x的操作轉(zhuǎn)移過來

    但是因為是下取整,所以有的jjj,可能除以多個xxx都能轉(zhuǎn)移到iii,不能簡單只加一個fjf_jfj?完事

    不妨反其道而行之,枚舉xxx,計算出區(qū)間[l,r][l,r][l,r]滿足j∈[l,r],?jx?=ij\in[l,r],\lfloor\frac{j}{x}\rfloor=ij[l,r],?xj??=i

    很簡單的數(shù)學(xué)計算一下,l=i?x,r=x?(i+1)?1l=i*x,r=x*(i+1)-1l=i?x,r=x?(i+1)?1

    fi+=∑j=lrfjf_i+=\sum_{j=l}^rf_jfi?+=j=lr?fj?

    時間復(fù)雜度是調(diào)和級數(shù),logn\rm lognlogn

后綴優(yōu)化即可,sumi=∑j=infjsum_i=\sum_{j=i}^nf_jsumi?=j=in?fj?

#include <cstdio> #include <iostream> using namespace std; #define int long long #define maxn 4000005 int n, mod; int f[maxn], sum[maxn];signed main() {scanf( "%lld %lld", &n, &mod );f[n] = sum[n] = 1;for( int i = n - 1;i;i -- ) {f[i] = sum[i + 1];for( int j = 2;i * j <= n;j ++ ) {int l = i * j, r = min( n, j * ( i + 1 ) - 1 );f[i] = ( f[i] + sum[l] - sum[r + 1] + mod ) % mod;}sum[i] = ( sum[i + 1] + f[i] ) % mod;}printf( "%lld\n", f[1] );return 0; }

E. Bottom-Tier Reversals

勉強中檔題

限制次數(shù)為5n2\frac{5n}{2}25n?,且只能操作奇數(shù)

暗示構(gòu)造,且相鄰奇偶綁定在一起才行

也就是說能否尋找一種構(gòu)造

555次操作內(nèi),將i,i?1i,i-1i,i?1放到相應(yīng)位置且以后不再操作這兩個數(shù),操作范圍變成i?2i-2i?2

observation : 每次操作[1,x][1,x][1,x]i?x?i+1i\leftrightarrow x-i+1i?x?i+1x+1x+1x+1為偶數(shù),所以i,x?i+1i,x-i+1i,x?i+1同奇偶

最后要滿足a[i]=i,下標(biāo)必須和值是同奇偶才會有解

判完無解后,555次操作這是可以做到的

  • n→1n\rightarrow 1n1構(gòu)造,每次滿足n,n?1n,n-1n,n?1iii為奇數(shù))放到相應(yīng)位置,每次操作后范圍n?=2n-=2n?=2
  • 找到iii的位置xxx(顯然xxx為奇數(shù)),第一次操作[1,x][1,x][1,x]區(qū)間,使得iii成為序列第一個
  • 找到i?1i-1i?1的位置yyy(顯然yyy為偶數(shù)),第二次操作[1,y?1][1,y-1][1,y?1]區(qū)間,使得iii成為i?1i-1i?1前面一個
  • 第三次操作[1,y+1][1,y+1][1,y+1],使得i?1i-1i?1成為序列第二個,iii成為序列第三個
  • 第四次操作[1,3][1,3][1,3],使得i?1i-1i?1成為序列第二個,iii成為序列第一個
  • 第五次操作[1,n][1,n][1,n],使得iii成為序列最后一個,i?1i-1i?1成為序列倒數(shù)第二個
  • 滿足條件
#include <cstdio> #include <algorithm> using namespace std; #define maxn 2025 int T, n, cnt; int p[maxn], id[maxn], ans[maxn << 2];void Reverse( int len ) {ans[++ cnt] = len;for( int i = 1;i <= len;i ++ )id[p[i]] = len - id[p[i]] + 1;reverse( p + 1, p + len + 1 ); }int main() {scanf( "%d", &T );next :while( T -- ) {cnt = 0;scanf( "%d", &n );for( int i = 1;i <= n;i ++ ) {scanf( "%d", &p[i] );id[p[i]] = i;}for( int i = 1;i <= n;i ++ )if( ( p[i] & 1 ) ^ ( i & 1 ) ) {printf( "-1\n" );goto next;}for( int i = n;i > 1;i -= 2 ) {Reverse( id[i] );int x = id[i - 1];Reverse( x - 1 );Reverse( x + 1 );Reverse( 3 );Reverse( i );}printf( "%d\n", cnt );for( int i = 1;i <= cnt;i ++ )printf( "%d ", ans[i] );printf( "\n" );}return 0; }

F. Top-Notch Insertions

困難

observation : 根據(jù)輸入的mmm個操作,最后序列上放的下標(biāo)是固定的

e.g. a1,a2,a3,a4,a5a_1,a_2,a_3,a_4,a_5a1?,a2?,a3?,a4?,a5?,操作(3,1) (4,1) (5,3)后,一定是a4,a3,a5,a1,a2a_4,a_3,a_5,a_1,a_2a4?,a3?,a5?,a1?,a2?,不管aia_iai?的值真的是多少

假設(shè)最后排序后的序列為[b1,b2,...,bn][b_1,b_2,...,b_n][b1?,b2?,...,bn?]

根據(jù)題目知,?i∈[1,n)bi≤bi+1\forall_i\in[1,n)\quad b_i\le b_{i+1}?i?[1,n)bi?bi+1?

考慮iii,如果a[i]>=a[i-1],不發(fā)生排序,并不能告訴我們什么東西,最多能知道最后bbb序列中aia_iai?排在ai?1a_{i-1}ai?1?的后面某個位置

那么如果aia_iai?插到jjj位置,能說明什么?

  • a[i]<a[j]
  • a[i]>=a[j-1]

同樣的不等式不能提供有用的幫助,反而重要的是a[i]<a[j]這個條件

我們非常關(guān)心aia_iai?,滿足ai?1a_{i-1}ai?1?被插入,這意味著ai?1<aia_{i-1}<a_iai?1?<ai?(注意是嚴(yán)格小于)

其余的相鄰兩個數(shù)關(guān)系可能是小于,可能是小于等于

換言之,最后的bbb序列,有些位置被打了標(biāo)記,強制該位置前一個的值嚴(yán)格小于改位置的值

設(shè)被標(biāo)記位置的個數(shù)為cnt\rm cntcnt,則最后的答案為(2n?cnt?1n)\binom{2n-cnt-1}{n}(n2n?cnt?1?)

  • 考慮ii∈[1,n)i\quad i\in[1,n)ii[1,n)bi≤bi+1b_{i}\le b_{i+1}bi?bi+1?,讓iii后面所有的bbb+1+1+1,變成bi<bi+1b_i<b_{i+1}bi?<bi+1?
  • 現(xiàn)在有?ibi<bi+1\forall i\quad b_i<b_{i+1}?ibi?<bi+1?
  • 最大的bbb取值可以為n+n?1?cntn+n-1-cntn+n?1?cnt
  • 相當(dāng)于在[1,maxB][1,\rm maxB][1,maxB]中選nnn互不相同的數(shù)

至于怎么找該被標(biāo)記的數(shù)

  • 相當(dāng)于需要一種數(shù)據(jù)結(jié)構(gòu)支持查找第kkk
  • 線段樹就可以了

注意本題只保證了mmm的限制,沒有nnn的限制

所以需要都回滾

那么就需要記錄每次問題后的操作點

#include <cstdio> #define maxn 200005 #define int long long #define mod 998244353 #define lson num << 1 #define rson num << 1 | 1 int n, m, T; bool vis[maxn]; int x[maxn], y[maxn], id[maxn], pos[maxn]; int fac[maxn << 1], inv[maxn << 1], t[maxn << 2];int qkpow( int x, int y ) {int ans = 1;while( y ) {if( y & 1 ) ans = ans * x % mod;x = x * x % mod;y >>= 1;}return ans; }void init( int n ) {fac[0] = inv[0] = 1;for( int i = 1;i <= n;i ++ ) fac[i] = fac[i - 1] * i % mod;inv[n] = qkpow( fac[n], mod - 2 );for( int i = n - 1;i;i -- ) inv[i] = inv[i + 1] * ( i + 1 ) % mod; }int C( int n, int m ) {return fac[n] * inv[m] % mod * inv[n - m] % mod; }void build( int num, int l, int r ) {t[num] = r - l + 1;if( l == r ) return;int mid = l + r >> 1;build( lson, l, mid );build( rson, mid + 1, r ); }int findKth( int k, int num = 1, int l = 1, int r = 2e5 ) {t[num] --;//找第K大的時候 順便完成-1的修改 if( l == r ) return l;int mid = l + r >> 1;if( k <= t[lson] ) return findKth( k, lson, l, mid );else return findKth( k - t[lson], rson, mid + 1, r ); }void modify( int k, int num = 1, int l = 1, int r = 2e5 ) {t[num] ++;if( l == r ) return;int mid = l + r >> 1;if( k <= mid ) modify( k, lson, l, mid );else modify( k, rson, mid + 1, r ); }int query( int k, int num = 1, int l = 1, int r = 2e5 ) {if( l == r ) return l;int mid = l + r >> 1;if( k <= t[lson] ) return query( k, lson, l, mid );else return query( k - t[lson], rson, mid + 1, r ); }signed main() {init( 4e5 );build( 1, 1, 2e5 );scanf( "%lld", &T );while( T -- ) {scanf( "%lld %lld", &n, &m );for( int i = 1;i <= m;i ++ )scanf( "%lld %lld", &x[i], &y[i] );int cnt = 0;for( int i = m;i;i -- ) {id[i] = query( y[i] + 1 );if( ! vis[id[i]] ) cnt ++, vis[id[i]] = 1;pos[i] = findKth( y[i] );}printf( "%lld\n", C( 2 * n - 1 - cnt, n ) );for( int i = m;i;i -- )vis[id[i]] = 0, modify( pos[i] );}return 0; } 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結(jié)

以上是生活随笔為你收集整理的Codeforces Round #740 (Div. 2, based on VK Cup 2021 - Final (Engine)) A-F全题解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。