KYOCERA Programming Contest 2021(AtCoder Beginner Contest 200) 题解
KYOCERA Programming Contest 2021(AtCoder Beginner Contest 200) 题解
哦淦我已经菜到被ABC吊打了。
A - Century
首先把当前年份减去\(1\),对应的世纪也减去\(1\),然后我们就发现第\(0\)到\(99\)年对应第\(0\)世纪,第\(100\)到\(199\)年对应第\(1\)世纪,以此类推。
答案就是\(\lfloor \frac {N-1} {100} \rfloor\)。这里\(\lfloor x \rfloor\)表示不超过\(x\)的最大整数。
#include<bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin>>n;
cout<<(n-1)/100+1<<endl;
return 0;
}
B - 200th ABC-200
乍一看答案会很大,然后爆long long。
其实假如当前数不是\(200\)的倍数的时候,把它后面连接上\(200\),结果一定是\(200\)的倍数,因为\(1000\)一定是\(200\)的倍数。
所以答案其实不会很大,最多就是\(976555175781\)(\(N=99999, K=20\))。
然后暴力做就好了。
#include<bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
long long n;
int k;
cin>>n>>k;
while(k){
if(n%200==0)n/=200,k--;
else n=n*1000+200,k--;
}
cout<<n;
return 0;
}
C - Ringo's Favorite Numbers 2
假如两个数相减是\(200\)的倍数,他们对\(200\)取模后,得到的结果一定相同。
然后就用前缀和记录在当前的位置之前有多少个数对\(200\)取模得到的结果和这个数对\(200\)取模的结果相同,并且把这个加入答案中就可以了。
只有我一开始以为差一定要是非负数然后被坑了么。
#include<bits/stdc++.h>
using namespace std;
int n,a[200005],c[205];
long long ans;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
ans+=c[a[i]%200];
c[a[i]%200]++;
}
cout<<ans;
return 0;
}
D - Happy Birthday! 2
首先还是把所有的数都对\(200\)取模。
然后我们可以想出来一种DP的状态表示方法:\(f_{i,j}\)表示已经处理了前\(i\)个数,选出来的\(B\)序列和\(C\)序列的差对\(200\)取模等于\(j\)。
这种状态的转移,可以枚举当前的数是放进\(B\)中还是\(C\)中,亦或是两个序列都不放。输出方案也只需要记录上一个状态的\(j\),然后反着操作一遍就好了。
但是它有一个问题,就是不能保证两个序列都是非空的。
我们可以再开一维,记录两个序列当中是不是有元素了:\(f_{i,j,k}\)表示已经处理了前\(i\)个数,选出来的\(B\)序列和\(C\)序列的差对\(200\)取模等于\(j\),\(k\)以子集的位掩码的形式记录两个序列是否非空。
子集的位掩码这个表述非常有点奇怪,具体来说就是:
- \(k=0\)表示两个序列都是空的。
- \(k=1\)表示一个序列都是空的。
- \(k=2\)表示另一个序列都是空的。
- \(k=3\)表示两个序列都是非空的。
(“一个”和“另一个”的表述是因为这不重要,我就懒得想了)
然后为了输出方案还要记录上一个状态的\(k\)是多少。
#include<bits/stdc++.h>
using namespace std;
int n,a[205],g[205][205][4],h[205][205][4];
bool f[205][205][4];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
a[i]%=200;
}
f[0][0][0]=1;
for(int i=1;i<=n;i++){
f[i][0][0]=1;
for(int j=0;j<200;j++){
for(int k=1;k<=3;k++){
if(f[i-1][(j+a[i])%200][k&1]){
f[i][j][k]=1;
g[i][j][k]=-1;
h[i][j][k]=k&1;
}
if(f[i-1][(j+a[i])%200][k]){
f[i][j][k]=1;
g[i][j][k]=-1;
h[i][j][k]=k;
}
if(f[i-1][j][k]){
f[i][j][k]=1;
}
if(f[i-1][(j-a[i]+200)%200][k&2]){
f[i][j][k]=1;
g[i][j][k]=1;
h[i][j][k]=k&2;
}
if(f[i-1][(j-a[i]+200)%200][k]){
f[i][j][k]=1;
g[i][j][k]=1;
h[i][j][k]=k;
}
}
}
}
if(!f[n][0][3]){
cout<<"NO";
return 0;
}
int x=n,y=0,z=3;
cout<<"YES\n";
vector<int> u,v;
while(x){
if(g[x][y][z]==1){
u.emplace_back(x);
z=h[x][y][z];
y=(y-a[x]+200)%200;
}else if(g[x][y][z]==-1){
v.emplace_back(x);
z=h[x][y][z];
y=(y+a[x])%200;
}
x--;
}
reverse(u.begin(),u.end());
cout<<u.size()<<' ';
for(int i:u)cout<<i<<' ';
cout<<'\n';
reverse(v.begin(),v.end());
cout<<v.size()<<' ';
for(int i:v)cout<<i<<' ';
return 0;
}
E - Patisserie ABC 2
这里我们可以想到先枚举三种属性的和是多少。然后我们可以定义\(tot(m)\),表示和为\(m\)的时候,一共有多少种组合方式。
然后由于每个属性的值都是\(1\)到\(n\)的限制,又到了激动人心的分类讨论环节。
首先我们把第一属性的值叫做\(i\),那么后两个属性的和就是\(m-i\)。
- \(2\leq m-i\leq n+1\):那么第二属性的取值范围就是\(1\)到\(m-i-1\),答案就是\(\sum_{\max(m-n-1,1)}^{\min(n,m-2)}m-i-1\)
- \(n+2\leq m-i\leq 2n\):那么第二属性的取值范围就是\(m-i-n\)到\(n\),答案就是\(\sum_{\max(1,m-2*n)}^{\min(n,m-n-2)}2n-(m-i)+1\)
那么:
\]
然后就可以枚举\(m\),快速的削减\(k\)的值,直到\(k\)小于等于\(tot(m)\)了,这时候我们就枚举第一属性\(i\),然后根据上文的分类讨论计算第二属性和第三属性的取值即可(同样是先快速削减\(k\),然后\(k\)小于等于当前第一属性对应取值种类数时输出答案)。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
ll k;
ll sum(int l,int r,int lv,int rv){
return (ll)(lv+rv)*(r-l+1)/2;
}
ll tot(int m){
ll res=0;
if(m<=2*n+1){
int l=max(1,m-n-1),r=min(n,m-2);
res+=sum(l,r,m-l-1,m-r-1);
}
if(m>n+2){
int l=max(1,m-2*n),r=min(n,m-n-2);
res+=sum(l,r,2*n-(m-l)+1,2*n-(m-r)+1);
}
return res;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>k;
for(int m=3;m<=3*n;m++){
if(k>tot(m)){
k-=tot(m);
continue;
}
for(int i=1;i<=n;i++)if(m-i<=n*2){
if(m-i<=n+1){
if(k>m-i-1){
k-=m-i-1;
continue;
}
cout<<i<<' '<<k<<' '<<m-i-k;
return 0;
}else{
if(k>2*n-(m-i)+1){
k-=2*n-(m-i)+1;
continue;
}
cout<<i<<' '<<m-i-n-1+k<<' '<<n+1-k;
return 0;
}
}
}
return 0;
}
F - Minflip Summation
由于我是看了题解才把这题做出来的,所以就照着题解翻译吧(还好意思讲)。
假如\(S\)不包含?同时\(K=1\)的解法
我们把所有左右相邻的,一个是\(0\)一个是\(1\)的位置(也就是\(S_i\neq S_{i+1}\)的位置\(i\))都数出来(比如10100能数出来\(3\)个)。
为了叙述方便,我们把它叫做“切换位置”(毕竟是从\(0\)切换到\(1\)或者从\(1\)切换到\(0\))。
然后发现一次操作,最多把它减少\(2\)(选择两个切换位置去操作),也可以减少\(1\)(选择一个切换位置,和一个开头/结尾)。
那么假如数出来\(D\)个位置,就需要\(\lfloor \frac D 2 \rfloor\)次操作解决。
这道题的解法
然后对于所有的这样的位置,我们记录他们的总和是\(A\):(主要是从AtCoder的题解上搬的,但是修了一点小锅)
\]
f(a,b)
=
\begin{cases}
\frac{1}{2} & \text{(if at least one of }a\text{ and }b\text{ is ?)} \\
1 & \text{(if neither }a\text{ nor }b\text{ is ? and }a\neq b\text{)} \\
0 & \text{(if neither }a\text{ nor }b\text{ is ? and }a = b\text{)} \\
\end{cases}
\end{eqnarray}
\]
然后答案似乎应该是\(\frac A 2\),不过还有一点问题:假如说一个串数出来奇数个切换位置,这种算法对于这个串会不会少算了半次操作?
我们可以发现,对于有奇数个切换位置的串,多添加一个切换位置后答案相同。
然后假如给\(A\)添加上这些串的个数,答案就是\(\frac A 2\)了。
这些串有一个性质:他们的开头和结尾,是不同的(毕竟切换了奇数次)。
然后这些串的个数就是\(2^{Kq} \times f(S_1,S_{|S|})\)。
然后答案就是\(\frac {A+2^{Kq} \times f(S_1,S_{|S|})} 2\),也就是:
\]
(特别地,这里把\(S_{|S|+1}\)看作是\(S_1\))
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int inv2=5e8+4;
ll qpow(ll a,ll n){
ll res=1;
while(n){
if(n&1)res=res*a%mod;
a=a*a%mod;
n>>=1;
}
return res;
}
int n,m,k,ans;
char s[100005];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>s>>k;
n=strlen(s);
if(n*k==1){cout<<0;return 0;}
for(int i=0;i<n;i++)m+=s[i]=='?';
m=qpow(2,(ll)k*m)*inv2%mod*k%mod;
for(int i=0;i<n;i++){
if(s[i]=='?'||s[(i+1)%n]=='?')ans=(ans+m)%mod;
else if(s[i]!=s[(i+1)%n])ans=(ans+m*2%mod)%mod;
}
cout<<(ll)ans*inv2%mod;
return 0;
}
KYOCERA Programming Contest 2021(AtCoder Beginner Contest 200) 题解的更多相关文章
- M-SOLUTIONS Programming Contest 2021(AtCoder Beginner Contest 232) 题解
目录 G - Modulo Shortest Path H - King's Tour 因为偷懒就只写G和H的题解了. G - Modulo Shortest Path 首先可以观察到对于一条从点\( ...
- AtCoder Beginner Contest 076
A - Rating Goal Time limit : 2sec / Memory limit : 256MB Score : 100 points Problem Statement Takaha ...
- AtCoder Beginner Contest 100 2018/06/16
A - Happy Birthday! Time limit : 2sec / Memory limit : 1000MB Score: 100 points Problem Statement E8 ...
- atcoder beginner contest 251(D-E)
Tasks - Panasonic Programming Contest 2022(AtCoder Beginner Contest 251)\ D - At Most 3 (Contestant ...
- AtCoder Beginner Contest 053 ABCD题
A - ABC/ARC Time limit : 2sec / Memory limit : 256MB Score : 100 points Problem Statement Smeke has ...
- AtCoder Beginner Contest 068 ABCD题
A - ABCxxx Time limit : 2sec / Memory limit : 256MB Score : 100 points Problem Statement This contes ...
- AtCoder Beginner Contest 184 题解
AtCoder Beginner Contest 184 题解 目录 AtCoder Beginner Contest 184 题解 A - Determinant B - Quizzes C - S ...
- AtCoder Beginner Contest 255(E-F)
Aising Programming Contest 2022(AtCoder Beginner Contest 255) - AtCoder E - Lucky Numbers 题意: 给两个数组a ...
- AtCoder Beginner Contest 052
没看到Beginner,然后就做啊做,发现A,B太简单了...然后想想做完算了..没想到C卡了一下,然后还是做出来了.D的话瞎想了一下,然后感觉也没问题.假装all kill.2333 AtCoder ...
随机推荐
- 「后端小伙伴来学前端了」Vuex进阶操作,让你的代码更加高效(简称如何学会偷懒 【手动狗头】)
学妹手机里的美照 前言 前一篇写了Vuex基本使用,用起来还稍稍有些繁琐,代码有很多 冗余的地方,这篇就带着大家用更简单的方式来使用Vuex(其实就是怎么更好的偷懒,用更少的代码来完之前的事情) 进入 ...
- Python描述符以及Property方法的实现原理
Python描述符以及Property方法的实现原理 描述符的定义: 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实了__get__(),__set__(),__delete__()中 ...
- myeclipse激活教程
1.安装,解压,下一步一下一步,一直到finish..结束 2.汉化破解激活:下载破解压缩包:解压
- 7.5 实现基于探针对pod中的访问的健康状态检查
1.pod的声明周期 取值 描述 Pending Pod 已被 Kubernetes 系统接受,但有一个或者多个容器尚未创建亦未运行.此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间, R ...
- 【状压dp】Hamiton路径
描述 给定一张 n(n≤20) 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径. Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点 ...
- 洛谷 P7323 - [WC2021] 括号路径(启发式合并)
题面传送门 emmmm----怎么评价这个题嘛...感觉纯论算法,此题根本谈不上难题,不过 WC 时候太智障只拿了个 48pts 就走人了.总之,技不如人,甘拜吓疯( 首先要注意到几件事情: 如果 \ ...
- Codeforces 1137F - Matches Are Not a Child's Play(LCT)
Codeforces 题面传送门 & 洛谷题面传送门 考虑将一个点 \(x\) 的编号变为当前所有点编号最大值 \(+1\) 会对每个点的删除时间产生怎么样的影响.由于编号最大的点肯定是最后一 ...
- BZOJ 3926 诸神眷顾的幻想乡
BZOJ 3926 诸神眷顾的幻想乡 开始看错题看成了每个点度数不超过20 后来翻了翻题解原来看错题的不止我一个 既然叶子数量不超过20,考虑树上的任何一条路径,以任何点为根时,如果它不是一条从上到下 ...
- python-django-分页处理
每个模型都有一个管理器,Manager 通过分页可以先加载一部分的数据内容,然后避免大量的查询带来的等待时间 应用场景是,排行榜,前十条或者 for i in range(100): ...: ... ...
- No.2 R语言在生物信息中的应用—模式匹配
目的: 1. 计算自定义模序在所有蛋白质的匹配位点和次数 2. 输出超过阈值的蛋白质序列到Hit_sequences.fasta 3. Hit_sequences.fasta中序列用小写字母,匹配用大 ...