KYOCERA Programming Contest 2021(AtCoder Beginner Contest 200)题解

news/2024/12/22 20:15:33/

文章目录

  • A - Century
  • B - 200th ABC-200
  • C - Ringo's Favorite Numbers 2
  • D - Happy Birthday! 2
  • E - Patisserie ABC 2
  • F - Minflip Summation

KYOCERA Programming Contest 2021(AtCoder Beginner Contest 200)

A - Century

简单的除以 200 200 200向上取整

B - 200th ABC-200

翻译成程序, w h i l e while while模拟即可

C - Ringo’s Favorite Numbers 2

差为 200 200 200倍数,则两个数同余 200 200 200,按照模完后的余数分类单独计算即可 C r i 2 C_{r_i}^2 Cri2

#include <cstdio>
#define maxn 200005
#define int long long
int n;
int A[maxn], r[205];signed main() {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ )scanf( "%lld", &A[i] ), r[A[i] % 200] ++;int ans = 0;for( int i = 0;i < 200;i ++ )ans += ( r[i] * ( r[i] - 1 ) / 2 );printf( "%lld\n", ans );return 0;
}

D - Happy Birthday! 2

d p i , j : dp_{i,j}: dpi,j: i i i个数中选某些数的和模 200 200 200余数为 j j j i i i必选)的方案数

直接大力转移,顺便用维克托儿记录下转移路径,方案数一旦等于 2 2 2即代表有解

因为 D P DP DP定义限制,两个序列的最后一个一定是一样的,这可能导致无法记录下最后一位不一样的方案

所以在原序列后面加一个 0 0 0,这样保证了两个数列的最后一位一定会是一样的

#include <cstdio>
#include <vector>
using namespace std;
#define int long long
#define maxn 205
vector < pair < int, int > > G[maxn][maxn];
int n;
int A[maxn], ans1[maxn], ans2[maxn];
int f[maxn][maxn];void print( int *ans, int &cnt, int p, int r ) {if( ! G[p][r].size() ) return;ans[++ cnt] = p;print( ans, cnt, G[p][r][0].first, G[p][r][0].second );
}signed main() {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ )scanf( "%lld", &A[i] );A[++ n] = 0;f[0][0] = 1;int pos, r; bool flag = 1;for( int i = 1;i <= n && flag;i ++ )for( int j = 0;j < i && flag;j ++ )for( int k = 0;k <= 200 && flag;k ++ )if( f[j][k] ) {f[i][( k + A[i] ) % 200] += f[j][k];G[i][( k + A[i] ) % 200].push_back( make_pair( j, k ) );if( f[i][( k + A[i] ) % 200] == 2 ) {pos = i, r = ( k + A[i] ) % 200;flag = 0;break;}}if( ! flag ) {printf( "Yes\n" );int cnt1 = 0, cnt2 = 0, t = 0;ans1[++ cnt1] = ans2[++ cnt2] = pos;print( ans1, cnt1, G[pos][r][0].first, G[pos][r][0].second );print( ans2, cnt2, G[pos][r][1].first, G[pos][r][1].second );if( pos == n ) t = 1;printf( "%lld", cnt1 - t );for( int i = cnt1;i > t;i -- )printf( " %lld", ans1[i] );printf( "\n%lld", cnt2 - t );for( int i = cnt2;i > t;i -- )printf( " %lld", ans2[i] );}elseprintf( "No\n" );return 0;
}

E - Patisserie ABC 2

d p i , j dp_{i,j} dpi,j表示选到第 i i i个数和为 j j j的方案数量

发现状态转移 d p i , j → d p i + 1 , j + 1 , d p i + 1 , j + 2 . . . d p i + 1 , j + n dp_{i,j}\rightarrow dp_{i+1,j+1},dp_{i+1,j+2}...dp_{i+1,j+n} dpi,jdpi+1,j+1,dpi+1,j+2...dpi+1,j+n是连续段转移,用差分即可

接着线性即可扫出总和,然后枚举美丽度,计算出味道的取值范围,进而确定味道,自然而然就确定了欢迎度

#include <cstdio>
#include <iostream>
using namespace std;
#define int long long
int dp[4][3000005];
int n, k;signed main() {scanf( "%lld %lld", &n, &k );dp[0][0] = 1;for( int i = 0;i < 3;i ++ ) {for( int j = 0;j <= i * n;j ++ ) {dp[i + 1][j + 1] += dp[i][j];dp[i + 1][j + n + 1] -= dp[i][j];}for( int j = 1;j <= ( i + 1 ) * n;j ++ )dp[i + 1][j] += dp[i + 1][j - 1];}int sum;for( int i = 3;i <= 3 * n;i ++ )if( dp[3][i] >= k ) {sum = i;break;}elsek -= dp[3][i];for( int beauty = 1;beauty <= n;beauty ++ ) {int minn = max( 1ll, sum - beauty - n );int maxx = min( n, sum - beauty - 1 );if( minn > maxx ) continue;if( k > maxx - minn + 1 ) k -= ( maxx - minn + 1 );else {int taste = minn + k - 1;return ! printf( "%lld %lld %lld\n", beauty, taste, sum - beauty - taste );}}return 0;
}

F - Minflip Summation

对于每种可能串 T T T,设 S = { i ∣ T i ≠ T i + 1 } , i ∈ [ 0 , l e n ) S=\{i|T_i≠T_{i+1}\},i∈[0,len) S={iTi=Ti+1},i[0,len),举个栗子T=010110S={0,1,2,4}

改写每次对一段l,r进行操作
{ l ≠ 1 α ( l − 1 ) r ≠ l e n − 1 α ( r ) \begin{cases} l≠1&&\alpha(l-1)\\ r≠len-1&&\alpha(r)\\ \end{cases}\\ {l=1r=len1α(l1)α(r)
α ( i ) : \alpha(i): α(i):如果 T i ≠ T i + 1 T_i≠T_{i+1} Ti=Ti+1,把 i i i S S S中删掉,否则加入其中

最后答案形态则是 S = ∅ S=\empty S=

不难发现,每次最多会从 S S S中删去两个数,所以最后的答案为 ⌈ t o t 2 ⌉ \lceil\frac{tot}{2}\rceil 2tot( t o t = ∣ S ∣ tot=|S| tot=S)

接下来考虑统计所有情况串中相邻两个字符不同的数量

c n t = 2 k q × ( k × ∑ i = 0 l e n − 1 f ( i , i + 1 ) + ( k − 1 ) × f l e n , 0 ) cnt=2^{kq}\times (k\times \sum_{i=0}^{len-1}f(i,i+1)+(k-1)\times f_{len,0}) cnt=2kq×(k×i=0len1f(i,i+1)+(k1)×flen,0)
f i , j = { 1 2 ( T i = ? ) ∣ ( T j = ? ) 1 ( T i ≠ T j ) 0 ( T i = T j ) f_{i,j}=\begin{cases} \frac{1}{2}&&&(T_i=?)|(T_{j}=?)\\ 1&&&(T_i≠T_j)\\ 0&&&(T_i=T_j) \end{cases} fi,j=2110(Ti=?)(Tj=?)(Ti=Tj)(Ti=Tj)

简单讨论一下

  • T i = T j = 0 / 1 T_i=T_j=0/1 Ti=Tj=0/1,那么对于 2 k q 2^{kq} 2kq种情况的字符串 i i i都不可能被算进 S S S,贡献 0 0 0
  • T i = 0 / 1 , T j = 1 / 0 , T i ≠ T j T_i=0/1,T_j=1/0,T_i≠T_j Ti=0/1,Tj=1/0,Ti=Tj,同理对于 2 k q 2^{kq} 2kq种情况的字符串 i i i都会被算进 S S S,贡献 1 1 1
  • 只有一个是 ? ? ?,那么只有 1 2 \frac{1}{2} 21的概率贡献 1 1 1,与另一个确定的字符不一样
  • 两个都是 ? ? ?,一共有 4 4 4种情况,两种相同(都是 1 1 1,都是 0 0 0),概率同样是 1 2 \frac{1}{2} 21

重复 K K K次原串,那么除了首尾少一次,其余都要 × k \times k ×k

但是这里仍然存在有一点小问题。

10100有三对相邻字符不一样,101001有四对相邻字符不一样,但是都需要花费 2 2 2次操作

我们本意是想上取整,但是在模意义下非常难搞

事实上,对于一个有奇数对相邻字符不一样的串,重复多次后,理想与实际操作之间是恒定的

举个例子,101100,三对不一样,花费 2 2 2,实际算的是 1 1 1,重复一遍101100101100,七对不一样,花费 4 4 4,实际算的是 3 3 3……

归纳一下,也就是说对于奇数对的串答案总是少了 1 1 1

加上这奇数对串的个数即为正确结果

不难发现,奇数对串的个数恰恰为首尾字符不相等的个数, 2 k q × f ( T 0 , T l e n − 1 ) 2^{kq}\times f(T_0,T_{len-1}) 2kq×f(T0,Tlen1)

所以最后的答案是 c n t = 2 k q × k × ∑ i = 0 l e n − 1 f ( i , ( i + 1 ) % l e n ) ) cnt=2^{kq}\times k\times \sum_{i=0}^{len-1}f(i,(i+1)\%len)) cnt=2kq×k×i=0len1f(i,(i+1)%len))

#include <cstdio>
#include <cstring>
#define int long long
#define mod 1000000007
#define maxn 100005
char s[maxn];
int k, inv, ans;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;
}int f( char x, char y ) {if( x == '?' || y == '?' ) return inv;else if( x != y ) return 1;else return 0;
}signed main() {scanf( "%s %lld", s, &k );int len = strlen( s );if( len * k == 1 ) return ! printf( "0\n" );int tot = 0;inv = qkpow( 2, mod - 2 );for( int i = 0;i < len;i ++ )tot += ( s[i] == '?' );int t = qkpow( 2, k * tot ) * k % mod;for( int i = 0;i < len;i ++ )ans = ( ans + t * f( s[i], s[( i + 1 ) % len] ) % mod ) % mod;ans = ans * inv % mod;printf( "%lld\n", ans );return 0;
}

http://www.ppmy.cn/news/913620.html

相关文章

KYOCERA Programming Contest 2022(AtCoder Beginner Contest 271)G.Access Counter(概率+矩阵快速幂优化dp)

题目 Takahashi布置了一个网页&#xff0c; 给定一个长为24的仅由A和T构成的字符串&#xff0c;表示每天整点能登进这个网页的概率 第i个字母如果是T&#xff0c;表示第i个整点的时候Takahashi有X(1<X<99)%的概率能登进去一次&#xff0c; 如果是A&#xff0c;表示第…

KYOCERA Programming Contest 2021(AtCoder Beginner Contest 200)E

首先考虑n^2的做法那就是 for(int i 1; i < 3; i){ for(int j 1; j < 3 * n; j){ for(int k 1; k < n; k){ dp[i][j k] dp[i - 1][j];我们从中可以看出 当 j 1的时候他对所有 j 1 ~ j n 那么 j 2 就对 j 2 ~ j n 1是有贡献的 所以我们只需求一个前缀和 即…

KYOCERA Programming Contest 2021(AtCoder Beginner Contest 200)

KYOCERA Programming Contest 2021&#xff08;AtCoder Beginner Contest 200&#xff09; A - CenturyB - 200th ABC-200C - Ringos Favorite Numbers 2D - Happy Birthday! 2E - Patisserie ABC 2 导读&#xff1a; 简单的题目&#xff0c;只说明题意&#xff0c;或者直接说明…

60道Linux面试题 ,让面试官无言以对

以下是Linux面试题目&#xff0c;答案一个个整理出来很麻烦&#xff0c;所以直接答案可以查看这里即可&#xff1a; http://www.yayihouse.com/yayishuwu/chapter/3629 1、Linux 软中断和工作队列的作用是什么?2、Linux 通过什么方式实现系统调用?3、linux如何唯一标识一个…

Hadoop 之 单机部署和测试(一)

Hadoop单机部署和测试 一.单机部署1.安装 JDK&#xff08;JDK11&#xff09;2.安装 HADOOP3.测试 一.单机部署 系统版本&#xff1a;cat /etc/anolis-release1.安装 JDK&#xff08;JDK11&#xff09; #!/bin/bashTOP_PATH$(pwd) JAVA_PATH/usr/local/java FILEls $TOP_PATH/…

Android 系统开发工具

Android 系统开发工具 1、SSH 服务与 Tabby Terminal1.1 配置 Ubuntu ssh 服务 2、Samba 服务器搭建3、Idegen Android Studio 查看源码3.1 修改android.iml文件 (可选) 4、AIdegen Android Studio 查看源码4.1 准备工作4.2 Android Studio 配置4.2.1 添加源码中的 jdk 和 sd…

Python代码样例列表

扫描左上角二维码&#xff0c;关注公众账号 数字货币量化投资&#xff0c;回复“Python例子”&#xff0c;获取以下600个Python经典例子源码 ├─algorithm│ Python用户推荐系统曼哈顿算法实现.py│ NFA引擎,Python正则测试工具应用示例.py│ Python datetime…

[iOS笔试600题]二、常识篇(共有72题)

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号&#xff1a;山青咏芝&#xff08;shanqingyongzhi&#xff09;➤博客园地址&#xff1a;山青咏芝&#xff08;https://www.cnblogs.com/strengthen/ &#xff09;➤GitHub地址&…