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\)

那么:

\[tot(i)=\sum_{\max(m-n-1,1)}^{\min(n,m-2)}(m-i-1)+\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的题解上搬的,但是修了一点小锅)

\[A = 2^{Kq} \times ( ( K \times \displaystyle \sum_{i=1}^{|S|-1} f(S_i,S_{i+1}) ) + (K-1) \times f(S_1,S_{|S|}))
\]
\[\begin{eqnarray}
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\),也就是:

\[2^{Kq} \times K \times \sum_{i=1}^{|S|} f(S_i,S_{i+1})
\]

(特别地,这里把\(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) 题解的更多相关文章

  1. M-SOLUTIONS Programming Contest 2021(AtCoder Beginner Contest 232) 题解

    目录 G - Modulo Shortest Path H - King's Tour 因为偷懒就只写G和H的题解了. G - Modulo Shortest Path 首先可以观察到对于一条从点\( ...

  2. AtCoder Beginner Contest 076

    A - Rating Goal Time limit : 2sec / Memory limit : 256MB Score : 100 points Problem Statement Takaha ...

  3. AtCoder Beginner Contest 100 2018/06/16

    A - Happy Birthday! Time limit : 2sec / Memory limit : 1000MB Score: 100 points Problem Statement E8 ...

  4. atcoder beginner contest 251(D-E)

    Tasks - Panasonic Programming Contest 2022(AtCoder Beginner Contest 251)\ D - At Most 3 (Contestant ...

  5. AtCoder Beginner Contest 053 ABCD题

    A - ABC/ARC Time limit : 2sec / Memory limit : 256MB Score : 100 points Problem Statement Smeke has ...

  6. AtCoder Beginner Contest 068 ABCD题

    A - ABCxxx Time limit : 2sec / Memory limit : 256MB Score : 100 points Problem Statement This contes ...

  7. AtCoder Beginner Contest 184 题解

    AtCoder Beginner Contest 184 题解 目录 AtCoder Beginner Contest 184 题解 A - Determinant B - Quizzes C - S ...

  8. AtCoder Beginner Contest 255(E-F)

    Aising Programming Contest 2022(AtCoder Beginner Contest 255) - AtCoder E - Lucky Numbers 题意: 给两个数组a ...

  9. AtCoder Beginner Contest 052

    没看到Beginner,然后就做啊做,发现A,B太简单了...然后想想做完算了..没想到C卡了一下,然后还是做出来了.D的话瞎想了一下,然后感觉也没问题.假装all kill.2333 AtCoder ...

随机推荐

  1. [bzoj1052]覆盖问题

    先二分答案,容易发现一定有一个正方形覆盖在角上(即有两条边在最X的地方),否则4个最X的点一定无法覆盖,然后暴力确定即可 1 #include<bits/stdc++.h> 2 using ...

  2. Redis | 第5章 Redis 中的持久化技术《Redis设计与实现》

    目录 前言 1. RDB 持久化 1.1 RDB 文件的创建与载入 1.2 自动间隔性保存 1.2.1 设置保存条件 1.2.2 dirty 计数器和 lastsave 属性 1.2.3 检查保存条件 ...

  3. C# Pechkin初始化一次后被锁住的问题

    Pechkin.dll可用于pdf的生成,常规用法网上都有介绍:https://www.cnblogs.com/felixnet/p/5143934.html 但是当在一个页面上执行过一次之后,再次就 ...

  4. 目前国内UI设计师的发展现状如何?

    在分析这个问题之前,我们先来说说如何优秀的UI设计师所需要具备的素质是什么,只有做到了以下几点,才有资格在这个行业生存下去的能力,也才有机会展望行业的未来前景. 一位合格的UI设计师必须做到以下3点: ...

  5. [NOI2020] 制作菜品

    看懂题目是生产第一要素. 考虑\(m = n - 1\)则必定有解.我们每次选择最小的和最大的拼在一起即可. 当\(m\)大于\(n\),那么我们只要每次选择最大的给他消掉即可. \(m = n - ...

  6. 洛谷 P6295 - 有标号 DAG 计数(生成函数+容斥+NTT)

    洛谷题面传送门 看到图计数的题就条件反射地认为是不可做题并点开了题解--实际上这题以我现在的水平还是有可能能独立解决的( 首先连通这个条件有点棘手,我们尝试把它去掉.考虑这题的套路,我们设 \(f_n ...

  7. LOJ #2769 -「ROI 2017 Day 1」前往大都会(单调栈维护斜率优化)

    LOJ 题面传送门 orz 斜率优化-- 模拟赛时被这题送走了,所以来写篇题解( 首先这个最短路的求法是 trivial 的,直接一遍 dijkstra 即可( 重点在于怎样求第二问.注意到这个第二问 ...

  8. LeeCode刷题笔记

    (本来想在LeeCode题目页面上做注释的,结果没找到位置,只好来这里了) 字符串部分: 14.最长公共前缀:编写一个函数来查找字符串数组中的最长公共前缀. 示例 1: 输入: ["flow ...

  9. DirectX12 3D 游戏开发与实战第十一章内容

    仅供个人学习使用,请勿转载.谢谢! 11.模板 模板缓冲区(stencil buffer)是一种"离屏"(off-screen)缓冲区,我们可以利用它来实现一些效果.模板缓冲区.后 ...

  10. Session和Cookie的原理,以及在分布式应用中出现的问题和解决方案

    产生原因 由于http协议是无状态的,同一个浏览器对服务器的两次请求之间是没有关系的,服务器认为两次请求都是全新的请求,不会记住上次请求成功的数据.然而现有的业务常常需要服务器能记住用户的访问情况, ...