文章目录

  • 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`上 的方案数

发现这个DPDPDP与iii没什么关系,可以使用矩阵快速幂优化

进行有效状态合并后才能转移不超时

  • 设SSS为root→uroot\rightarrow uroot→u的路径,TTT为root→vroot\rightarrow vroot→v的路径,那么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) 题解相关推荐

  1. Educational Codeforces Round 107 (Rated for Div. 2)

    Educational Codeforces Round 107 (Rated for Div. 2) 题号 题目 知识点 A Review Site 签到 B GCD Length 思维+构造 C ...

  2. Educational Codeforces Round 117 (Rated for Div. 2)题解(A~D)

    Educational Codeforces Round 117 (Rated for Div. 2) 今天这场没打,赛后从九点半到十一点把前面四个题目给补了一下,E题明天有时间看看能不能弄出来. A ...

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

    看看时间还有十几分钟,开不出来题了,写个题解 A. Cut the Triangle 检查是不是直角边平行于坐标轴的直角三角形即可 这里可以用异或来写,代码较为简洁,我就不改了,直接贴上我的丑代码 c ...

  4. Educational Codeforces Round 133 (Rated for Div. 2) 题解 CD

    D: 这是一道好dp(对我来说) 我做的时候有想过正解那个方式当考虑到可能有重复就没有深入思考了 假设dp[i][j]代表第i次j的方案数 此时我们可以发现dp[i][j]=sum(dp[i-1][j ...

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

    Educational Codeforces Round 105 (Rated for Div. 2) A. ABC String 枚举ABC分别为"( "和 " )&q ...

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

    Educational Codeforces Round 36 (Rated for Div. 2) 题目的质量很不错(不看题解做不出来,笑 Codeforces 920C 题意 给定一个\(1\)到 ...

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

    Educational Codeforces Round 76 题解 比赛链接 A. Two Rival Students #include<bits/stdc++.h> using na ...

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

    目录 A.CF1398A Bad Triangle(模拟) B.CF1398B Substring Removal Game(贪心) C.CF1398C Good Subarrays(映射) D.CF ...

  9. Educational Codeforces Round 92 (Rated for Div. 2)题解(A-C)

    目录 A.LCM Problem B.Array Walk C. Good String A.LCM Problem 题意:给定两个整数定义的闭区间[l,r][l,r][l,r],让你在区间内找出两个 ...

最新文章

  1. php-fpm定义成集群资源时报错解决方法
  2. 【Android】安卓布局文件中xmlns属性
  3. Linux内核启动速度优化,嵌入式Linux启动时间优化的秘密之五-Bootloader
  4. 组件注册——@ComponentScan自动扫描组件指定扫描规则
  5. label mpchart 饼图_Origin系列:绘制柱状堆积图
  6. 5.Underfitting and Overfitting
  7. influxdb入库mysql_InfluxDb(3)基本操作
  8. python第三十一课--递归(3.递归的弊端)
  9. python要学多久可以找到工作-学习Python多久能找到工作?老男孩Python开发培训
  10. 关于《大道至简》第八章的收获
  11. java基础之static
  12. Linux 下如何彻底卸载MySQL数据库
  13. 智能硬件不止树莓派,八款优秀智能硬件开源项目推荐
  14. Word打开文件错误提示用文本恢复转换器打开文件
  15. 离散数学 2.3 Functions
  16. 云班课作业互评(python3+selenium)
  17. 枫叶HD高清视频转换器 V10.2.2.0 官方安装版
  18. 利用redis缓存对 list集合中的数据 进行分页操作(一)
  19. 编程基础知识(变简单的进制转换)
  20. NLP:文本情感分析快速入门

热门文章

  1. matlab菲涅尔衍射_有问必答——SYNOPSYS安装体验课堂——可以设计菲涅尔透镜吗?...
  2. mysql怎么查看索引情况_mysql 查看索引使用情况
  3. 今日笔记!——分析Java应用性能
  4. 在python中strip_python中strip()函数怎么用?
  5. python base64编码_JS和Python实现AES算法
  6. 米家扫地机器人充满电需要多长时间_米家扫地机器人充满电后能工作多久?
  7. 后端学习 - Spring5
  8. Mysql@和@@符号的详细使用说明
  9. [PAT乙级]1043 输出PATest
  10. [Java基础]ListIterator