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 ...
随机推荐
- Java-ASM框架学习-java概念转字节码概念
前言 当我们操作字节码的时候,都是和字节码的概念打交道,这让我们很困扰,asm也想到了这点,为了方便,它提供了一个可以把java概念转化为字节码概念的类 import org.objectweb.as ...
- 【CSS】水平居中和垂直居中
水平居中和垂直居中 2019-11-12 15:35:37 by冲冲 1.水平居中 (1)父级元素是行内元素,子级元素是行内元素,子级元素水平居中 ① 设置父级元素为块级元素 display:bl ...
- 莫比乌斯反演&各种筛法
不学莫反,不学狄卷,就不能叫学过数论 事实上大概也不是没学过吧,其实上赛季头一个月我就在学这东西,然鹅当时感觉没学透,连杜教筛复杂度都不会证明,所以现在只好重新来学一遍了(/wq 真·实现了水平的负增 ...
- CF#581 (div2)题解
CF#581 题解 A BowWow and the Timetable 如果不是4幂次方直接看位数除以二向上取整,否则再减一 #include<iostream> #include< ...
- windows下的python安装pysam报错
安装pysam时报错: 指定版本仍报错: 使用pysam-win安装: 但是import时不行: 貌似pysam在windows下难以正常配置,还是在Linux中用吧. https://www.jia ...
- Docker实用命令介绍
Docker实用命令介绍 1. docker启动.关闭.停止 ╭─wil-xz in ~ 12:15:44 ╰─٩(ŏ﹏ŏ.)۶ service docker restart Redirecting ...
- Perl 常用的小细节总结
1.命令行:perl -c perl.pl #用来检验Perl脚本有没有错误: 2.vi perl.pl打开脚本,ESC+:set nu 回车,给每行加上行号:
- vc控制台程序关闭事件时的正确处理方式
百度可以找到很多关于这个问题解决的方法 关键控制台API函数:SetConsoleCtrlHandler 在支持C++ 11以上的编译器中,你可以这么做. SetConsoleCtrlHandler( ...
- 使用Postman轻松实现接口数据关联
Postman Postman是一款非常流行的HTTP(s)接口测试工具,入门简单,界面美观,功能强大.作为一个测试/开发工程师,这是一款必须要会用的工具.今天以一个实际的案例,来介绍下Postman ...
- YARP+AgileConfig 5分钟实现一个支持配置热更新的代理网关
YARP 是微软开源的一个反向代理项目,英文名叫 Yet Another Reverse Proxy .所谓反向代理最有名的那就是 nginx 了,没错 YARP 也可以用来完成 nginx 的大部分 ...