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 ...
随机推荐
- 【JavaSE】类与类的关系--UML
类(对象/接口)之间的关系 -- UML类图展现 2019-07-14 14:37:19 by冲冲 在面向对象程序设计时,类与类之间的关系主要分为:继承,实现,依赖,关联,聚合,组合等6种关系. ...
- 多线程05.thread不知道的知识
Thread thread = new Thread(); // init(null, null, "Thread-" + nextThreadNum(), 0); //init( ...
- 从零开始学Kotlin第二课
字符串模板 fun main(args:Array<String>){ //主函数main方法 println(diaryGenerater("天安门")); } // ...
- Java编程之学习技巧
**本人博客网站 **IT小神 www.itxiaoshen.com 找到技术点 首先得知道自己要学习技术是什么?不管是来自同事.技术大牛推荐还是通过搜索引擎得到,或者另有出处如.技术交流群.技术论坛 ...
- Feed系统设计分析(类似微博的用户动态分享问题)
Feed系统 最近在研究一个个人动态分享平台,对动态的推送方式有些疑惑,于是研究到了以下结果. 简介 在信息学里面,Feed其实是一个信息单元,比如一条朋友圈状态.一条微博.一条资讯或一条短视频等,所 ...
- 用pipenv管理python虚拟环境
python的虚拟环境可以为项目创建一个独立的环境,能够解决使用不同版本依赖给项目带来冲突的麻烦.创建虚拟环境的方式有很多种,pipenv会自动帮你管理虚拟环境和依赖文件,并且提供了一系列命令和选项来 ...
- 流量限制器(Flux Limiter)
内容翻译自Wikipedia Flux limiter 流量限制器(Flux limiters)应用在高精度格式中-这种数值方法用来求解科学与工程问题,特别是由偏微分方程(PDE's)描述的流体动力学 ...
- R语言与医学统计图形-【27】ggplot2图形组合、字体、保存
ggplot2绘图系统--图形组合.字体选择.保存输出 1.图形组合 一页多图在基础包中利用par和layout函数来切分画布. ggplot2是先铺好网格背景,再进行绘图,所以要通过切分网格背景来实 ...
- GO 语言使用copy 拷贝切片的问题
使用copy,直接改变原片的值,而不是先创建一个副本.
- A Child's History of England.5
Above all, it was in the Roman time, and by means of Roman ships, that the Christian Religion was fi ...