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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Educational Codeforces Round 107 (Rated for Div. 2) 题解

發布時間:2023/12/3 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Educational Codeforces Round 107 (Rated for Div. 2) 题解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • A. Review Site
  • B. GCD Length
  • C. Yet Another Card Deck
  • D. Min Cost String
  • E. Colorings and Dominoes
  • F. Chainword
  • G. Chips on a Board

Educational-Round-107

A. Review Site

都給了兩臺機子,直接把所有只會投②的扔到一臺,其余的全是另一臺

就是類型一和類型三的數量求和

#include <cstdio> int T, n, ans;int main() {scanf( "%d", &T );while( T -- ) {scanf( "%d", &n );ans = 0;for( int i = 1, x;i <= n;i ++ ) {scanf( "%d", &x );if( x == 2 ) continue;else ans ++;}printf( "%d\n", ans );}return 0; }

B. GCD Length

直接強制gcd=10c?1gcd=10^{c-1}gcd=10c?1,假設xxx的位數小于yyy的位數,則x=10a?1,y=10b?1+gcdx=10^{a-1},y=10^{b-1}+gcdx=10a?1,y=10b?1+gcd

加上gcdgcdgcd恰好保證了gcd(xgcd,ygcd)=1gcd(\frac{x}{gcd},\frac{y}{gcd})=1gcd(gcdx?,gcdy?)=1的性質

#include <cstdio> #include <iostream> using namespace std; int T, n, a, b, c, A, B, C;int qkpow( int x, int y ) {int ans = 1;while( y ) {if( y & 1 ) ans = ans * x;x = x * x;y >>= 1;}return ans; }int main() {scanf( "%d", &T );while( T -- ) {scanf( "%d %d %d", &a, &b, &c );bool flag = 0;if( a > b ) swap( a, b ), flag = 1;A = qkpow( 10, a - 1 );C = qkpow( 10, c - 1 );B = qkpow( 10, b - 1 );if( flag ) printf( "%d %d\n", B + C, A );else printf( "%d %d\n", A, B + C );}return 0; }

C. Yet Another Card Deck

真正有用的只有顏色第一次出現的位置

對于一個顏色第一次被操作,可以用樹狀數組統計該位置后面有多少顏色被操作過,那么最初其位置就會后移

對于多次被操作的顏色,因為顏色不超過五十種,顯然可以暴力移動顏色

#include <cstdio> #define maxn 300005 int n, Q, x; int a[maxn], pos[maxn], vis[maxn], t[maxn], ans[maxn];int lowbit( int x ) {return x & ( -x ); }void add( int x ) {x = n - x + 1;for( int i = x;i <= n;i += lowbit( i ) )t[i] ++; }int query( int x ) {x = n - x + 1; int ans = 0;for( int i = x;i;i -= lowbit( i ) )ans += t[i];return ans; }int main() {scanf( "%d %d", &n, &Q );for( int i = 1;i <= n;i ++ ) {scanf( "%d", &a[i] );if( ! pos[a[i]] ) pos[a[i]] = i;}int cnt = 0;for( int i = 1;i <= Q;i ++ ) {scanf( "%d", &x );if( ! vis[x] ) {printf( "%d\n", pos[x] + query( pos[x] ) );cnt ++;for( int j = cnt;j > 1;j -- )ans[j] = ans[j - 1];ans[1] = x;add( pos[x] );vis[x] = 1;}else {for( int j = 1;j <= cnt;j ++ ) if( ans[j] == x ) {printf( "%d\n", j );for( int k = j;k > 1;k -- )ans[k] = ans[k - 1];ans[1] = x;break;}}}return 0; }

D. Min Cost String

找規律a ab ac ad ae ...a[k] b bc bd be bf... b[k]...[k]

高級解釋:剩余系(同余)

#include <cstdio> #define maxn 200005 int n, k, cnt; char s[maxn];int main() {scanf( "%d %d", &n, &k );for( int i = 0;i < k;i ++ ) {s[cnt ++] = i + 'a';for( int j = i + 1;j < k;j ++ )s[cnt ++] = i + 'a', s[cnt ++] = j + 'a';}int ip = 0;for( int i = 1;i <= n;i ++ )printf( "%c", s[ip % cnt] ), ip ++;return 0; }

E. Colorings and Dominoes

利用概率論求解應該是更簡單的,求出一張多米諾骨牌放在i,ji,ji,j位置的概率乘總方案數就是貢獻

行多米諾骨牌只能用紅色,列多米諾骨牌只能用藍色

因此行列是彼此獨立的,可以分開做,下面以行為例

考慮DPDPDP求概率,設dpi,0/1:idp_{i,0/1}:idpi,0/1?:i 位置是一張多米諾骨牌的左邊0/右邊1

dpi,0=(dpi?1,1+12)×12dp_{i,0}=(dp_{i-1,1}+\frac{1}{2})\times \frac{1}{2}dpi,0?=(dpi?1,1?+21?)×21?12\frac{1}{2}21?是有可能i?1i-1i?1是藍色,天然隔絕一行中的兩段,iii此時滿足做左邊的條件

dpi,1=dpi?1,0×12dp_{i,1}=dp_{i-1,0}\times \frac{1}{2}dpi,1?=dpi?1,0?×21?

12\frac{1}{2}21?是表示iii為紅色的概率

這個DPDPDP狀態轉移其實只與長度有關,因此只需要提取出一行中連續段長度即可

#include <cstdio> #define int long long #define mod 998244353 #define maxn 300000 int n, m, cnt; char s[maxn]; int row[maxn + 5], col[maxn + 5]; int dp[maxn + 5][2];int id( int i, int j ) {return i * m + j; }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; }signed main() {scanf( "%lld %lld", &n, &m );for( int i = 0;i < n;i ++ ) {scanf( "\n" );for( int j = 0;j < m;j ++ ) {scanf( "%c", &s[id( i, j )] );cnt += ( s[id( i, j )] == 'o' );}}int inv = qkpow( 2, mod - 2 ), All = qkpow( 2, cnt );dp[1][0] = inv; for( int i = 2;i <= maxn;i ++ ) {dp[i][0] = ( dp[i - 1][1] + inv ) * inv % mod;//還有可能是i-1為藍色(概率為1/2)斷開了行的兩段dp[i][1] = dp[i - 1][0] * inv % mod;}int ans = 0;for( int i = 0;i < n;i ++ ) {for( int j = 0;j < m;j ++ ) {row[id( i, j )] = col[id( i, j )] = 1;if( i > 0 && s[id( i - 1, j )] == 'o' ) row[id( i, j )] = row[id( i - 1, j )] + 1;if( j > 0 && s[id( i, j - 1 )] == 'o' ) col[id( i, j )] = col[id( i, j - 1 )] + 1;if( s[id( i, j )] == 'o' ) ans = ( ans + dp[row[id( i, j )]][1] + dp[col[id( i, j )]][1] ) % mod;} }printf( "%lld\n", ans * All % mod );return 0; }

F. Chainword

對單詞建立trie樹

當在s的末尾增加一個字符的時候

相當于在 trie樹上從一個結點u沿著一條轉移邊走到另外一個結點v

當然,也可以在某個字符串的結束位置不繼續往下走,而是跳回到根節點

fi,u,v:f_{i,u,v}:fi,u,v?: 表示sss加入了iii個字符,上方的線在trie的結點uuu上,下方的線在``trie的結點v`上 的方案數

發現這個DPDPDPiii沒什么關系,可以使用矩陣快速冪優化

進行有效狀態合并后才能轉移不超時

  • SSSroot→uroot\rightarrow urootu的路徑,TTTroot→vroot\rightarrow vrootv的路徑,那么SSS一定是TTT的前綴/后綴
  • fi,u,v=fi,v,u?(u,v)(v,u)f_{i,u,v}=f_{i,v,u}\Rightarrow (u,v)(v,u)fi,u,v?=fi,v,u??(u,v)(v,u)可以視為一個狀態

找到滿足第一種要求的狀態的點:從(0,0)(0,0)(0,0)開始bfsbfsbfs,每次轉移的時候枚舉最后一個字符,所有能訪問到的結點

#include <map> #include <queue> #include <cstdio> #include <cstring> #include <iostream> using namespace std; #define int long long #define mod 998244353 #define Pair pair < int, int > queue < Pair > q; map < Pair, int > mp; int n, m; char s[10];struct matrix {int v[170][170];matrix() {memset( v, 0, sizeof( v ) );}matrix operator * ( matrix &t ) const {matrix ans;for( int i = 0;i <= 160;i ++ )for( int j = 0;j <= 160;j ++ )for( int k = 0;k <= 160;k ++ )ans.v[i][j] = ( ans.v[i][j] + v[i][k] * t.v[k][j] % mod ) % mod;return ans;} }O;matrix qkpow( matrix x, int y ) {matrix ans;for( int i = 0;i <= 160;i ++ )ans.v[i][i] = 1;while( y ) {if( y & 1 ) ans = ans * x;x = x * x;y >>= 1;}return ans; }struct tree {int End, son[26];tree() {memset( son, -1, sizeof( son ) );} }trie[170];int cnt;void insert() {int len = strlen( s + 1 ), now = 0;for( int i = 1;i <= len;i ++ ) {if( trie[now].son[s[i] - 'a'] == -1 )trie[now].son[s[i] - 'a'] = ++ cnt;now = trie[now].son[s[i] - 'a'];}trie[now].End = 1; }int ID( int x, int y ) {if( x > y ) swap( x, y );if( ! mp.count( make_pair( x, y ) ) ) {mp[make_pair( x, y )] = mp.size();q.push( make_pair( x, y ) );}return mp[make_pair( x, y )]; }signed main() {scanf( "%lld %lld", &n, &m );for( int i = 1;i <= n;i ++ ) {scanf( "%s", s + 1 );insert();}mp[make_pair( 0, 0 )] = 0;q.push( make_pair( 0, 0 ) );while( ! q.empty() ) {Pair now = q.front(); q.pop();int id = ID( now.first, now.second );for( int i = 0;i < 26;i ++ ) {int x = trie[now.first].son[i], y = trie[now.second].son[i];if( x == -1 || y == -1 ) continue;O.v[id][ID( x, y )] ++;if( trie[x].End ) O.v[id][ID( 0, y )] ++;if( trie[y].End ) O.v[id][ID( x, 0 )] ++;if( trie[x].End && trie[y].End ) O.v[id][ID( 0, 0 )] ++;}}printf( "%lld\n", qkpow( O, m ).v[0][0] );return 0; }

G. Chips on a Board

兩人在玩Nim博弈游戲,有異或結論:在[l,r][l,r][l,r]范圍內所有棋子到lll的距離的異或和

000則后手勝,不為000則先手勝

距離差在異或下的運算法則不好維護

考慮拆成二進制下每位獨立維護

發現可以用倍增(倍增的本質就是二進制下每一位單獨貢獻)

dpi,j:[i,i+2j)dp_{i,j}:[i,i+2^j)dpi,j?:[i,i+2j)區間內的棋子到iii的距離異或和

最高位的貢獻是獨立于所有比其小的貢獻的

cnti:cnt_i:cnti?:iii列的棋子個數

dpi,j=dpi,j?1?dpi+2j?1,j?1?[cnti+2j?1?cnti+2j?1?1mod2=1]2j?1dp_{i,j}=dp_{i,j-1}\bigoplus dp_{i+2^{j-1},j-1}\bigoplus [cnt_{i+2^j-1}-cnt_{i+2^{j-1}-1}\mod 2 =1]2^{j-1}dpi,j?=dpi,j?1??dpi+2j?1,j?1??[cnti+2j?1??cnti+2j?1?1?mod2=1]2j?1

最后求答案異或和,也是枚舉每位單獨計算貢獻

#include <cstdio> #define maxn 200005 int n, m, Q; int dp[maxn][20]; int bit[maxn], cnt[maxn];int main() {scanf( "%d %d", &n, &m );for( int i = 1, x;i <= n;i ++ )scanf( "%d", &x ), cnt[x] ++;for( int i = 1;i <= m;i ++ )cnt[i] += cnt[i - 1];bit[0] = -1;for( int i = 1;i <= m;i ++ )bit[i] = bit[i >> 1] + 1;for( int j = 1;j < 20;j ++ )for( int i = 1;i <= m;i ++ )if( i + ( 1 << j ) - 1 <= m )dp[i][j] = dp[i][j - 1] ^ dp[i + ( 1 << j - 1 )][j - 1] ^ ( ( ( cnt[i + ( 1 << j ) - 1] - cnt[i + ( 1 << j - 1 ) - 1] ) & 1 ) * ( 1 << j - 1 ) );scanf( "%d", &Q );while( Q -- ) {int ans = 0, l, r;scanf( "%d %d", &l, &r );for( int i = bit[m];~ i;i -- )if( l + ( 1 << i ) <= r ) {ans ^= dp[l][i];l += ( 1 << i );if( ( cnt[r] - cnt[l - 1] ) & 1 )ans ^= ( 1 << i );}printf( "%c", ans ? 'A' : 'B' );}return 0; }

總結

以上是生活随笔為你收集整理的Educational Codeforces Round 107 (Rated for Div. 2) 题解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。