Codeforces Round #740 (Div. 2, based on VK Cup 2021 - Final (Engine)) A-F全题解
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
簡單題
分總場數n=a+bn=a+bn=a+b的奇偶討論,假設以Alice Bob第一場發球
算出每個人發球的場數,計算出某個勝場不夠的人至少要break多少場
之后只能兩人相互break相同場數才能保持彼此贏的場數滿足a/b
用vis[i]記錄break恰好iii場是否可以,每次都是+2+2+2暴力加
碰到已經打過標記的就可以跳出循環
#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個怪物殺死獲得提升的機會,然后要求嚴格大于怪物生命值,所以+1+1+1
將這個值定義為洞穴的通關要求,升序排列洞穴
每次通過一個洞穴力量值就會增加洞穴的怪物數那么大
在下一個洞穴前判斷能否通過,不能就加上差的力量值
#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題
設計fi:f_i:fi?: 移動到格子iii的方案數,由n→1n\rightarrow 1n→1轉移
-
iii后面的每個格子都可以通過?x-x?x的操作轉移過來
fi+=∑j=i+1nfjf_i+=\sum_{j=i+1}^nf_jfi?+=∑j=i+1n?fj?
-
iii后面的格子(以2?i2*i2?i開始)都可以通過/x/x/x的操作轉移過來
但是因為是下取整,所以有的jjj,可能除以多個xxx都能轉移到iii,不能簡單只加一個fjf_jfj?完事
不妨反其道而行之,枚舉xxx,計算出區間[l,r][l,r][l,r]滿足j∈[l,r],?jx?=ij\in[l,r],\lfloor\frac{j}{x}\rfloor=ij∈[l,r],?xj??=i
很簡單的數學計算一下,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?
時間復雜度是調和級數,logn\rm lognlogn
后綴優化即可,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
勉強中檔題
限制次數為5n2\frac{5n}{2}25n?,且只能操作奇數
暗示構造,且相鄰奇偶綁定在一起才行
也就是說能否尋找一種構造
在555次操作內,將i,i?1i,i-1i,i?1放到相應位置且以后不再操作這兩個數,操作范圍變成i?2i-2i?2
observation : 每次操作[1,x][1,x][1,x],i?x?i+1i\leftrightarrow x-i+1i?x?i+1,x+1x+1x+1為偶數,所以i,x?i+1i,x-i+1i,x?i+1同奇偶
最后要滿足a[i]=i,下標必須和值是同奇偶才會有解
判完無解后,555次操作這是可以做到的
- 從n→1n\rightarrow 1n→1構造,每次滿足n,n?1n,n-1n,n?1(iii為奇數)放到相應位置,每次操作后范圍n?=2n-=2n?=2
- 找到iii的位置xxx(顯然xxx為奇數),第一次操作[1,x][1,x][1,x]區間,使得iii成為序列第一個
- 找到i?1i-1i?1的位置yyy(顯然yyy為偶數),第二次操作[1,y?1][1,y-1][1,y?1]區間,使得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成為序列倒數第二個
- 滿足條件
F. Top-Notch Insertions
困難
observation : 根據輸入的mmm個操作,最后序列上放的下標是固定的
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?的值真的是多少
假設最后排序后的序列為[b1,b2,...,bn][b_1,b_2,...,b_n][b1?,b2?,...,bn?]
根據題目知,?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],不發生排序,并不能告訴我們什么東西,最多能知道最后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]這個條件
我們非常關心aia_iai?,滿足ai?1a_{i-1}ai?1?被插入,這意味著ai?1<aia_{i-1}<a_iai?1?<ai?(注意是嚴格小于)
其余的相鄰兩個數關系可能是小于,可能是小于等于
換言之,最后的bbb序列,有些位置被打了標記,強制該位置前一個的值嚴格小于改位置的值
設被標記位置的個數為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?
- 現在有?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
- 相當于在[1,maxB][1,\rm maxB][1,maxB]中選nnn個互不相同的數
至于怎么找該被標記的數
- 相當于需要一種數據結構支持查找第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; } 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的Codeforces Round #740 (Div. 2, based on VK Cup 2021 - Final (Engine)) A-F全题解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Windows系统怎么输入特殊符号?
- 下一篇: 【地狱副本】数据结构之线段树Ⅲ——区间最