Atcoder Beginner Contest 380 题解 (A-G)
Atcoder Beginner Contest 380 题解 (A-G)
A - 123233
#include<bits/stdc++.h>
using namespace std;
using i64=long long;
void Showball(){
string s;
cin>>s;
sort(s.begin(),s.end());
if(s=="122333") cout<<"Yes\n";
else cout<<"No\n";
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
//cin>>t;
while(t--){
Showball();
}
return 0;
}
B - Hurdle Parsing
#include<bits/stdc++.h>
using namespace std;
using i64=long long;
void Showball(){
string s;
cin>>s;
int cnt=0;
for(auto c:s){
if(c=='|'){
if(cnt) cout<<cnt<<" ";
cnt=0;
}else{
cnt++;
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
//cin>>t;
while(t--){
Showball();
}
return 0;
}
C - Move Segment
模拟乱搞,下标,边界有点烦。
#include<bits/stdc++.h>
using namespace std;
using i64=long long;
void Showball(){
int n,k;
cin>>n>>k;
string s;
cin>>s;
vector<int> a,b;
string order="";
for(int i=0,j=0;i<n;){
while(j<n&&s[i]==s[j]) j++;
order+=s[i];
if(s[i]=='1') a.push_back(j-i);
else b.push_back(j-i);
i=j;
}
int one=0,zero=0;
a[k-2]+=a[k-1];
for(auto c:order){
if(c=='1'){
if(one==k-1) {
one++;
continue;
}
for(int i=0;i<a[one];i++) cout<<1;
one++;
}else{
for(int i=0;i<b[zero];i++) cout<<0;
zero++;
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
//cin>>t;
while(t--){
Showball();
}
return 0;
}
D - Strange Mirroring 思维
经典性质,以
我们发现性质:如果当前位
不妨令原串为
取模求位置即可。
#include<bits/stdc++.h>
using namespace std;
using i64=long long;
void Showball(){
string s,t;
cin>>s;
int n=s.size();
t=s;
for(int i=0;i<n;i++){
if(islower(t[i])) t[i]=char(t[i]-32);
else t[i]=char(t[i]+32);
}
int q;
cin>>q;
while(q--){
i64 x;
cin>>x;
x--;
i64 p=x/n;
int r=x%n;
if(__builtin_popcountll(p)&1) cout<<t[r]<<" ";
else cout<<s[r]<<" ";
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
//cin>>t;
while(t--){
Showball();
}
return 0;
}
E - 1D Bucket Tool 并查集
可以用并查集来进行维护相同的颜色。只需要维护出这段颜色的左端点以及区间长度即可。
对于查询
然后原本区间颜色数量减去区间长度大小。更新颜色,并且维护新颜色的数量。注意还需要判断左右相邻区间颜色是否相同,然后维护颜色并查集即可。
#include<bits/stdc++.h>
using namespace std;
using i64=long long;
struct DSU{
vector<int> p, sz;
DSU(int n) : p(n + 1), sz(n + 1, 1){
iota(p.begin(), p.end(), 0);
}
int find(int x){
return p[x] == x ? x : p[x] = find(p[x]);
}
bool same(int x, int y) {
return find(x) == find(y);
}
bool merge(int x, int y){
x = find(x), y = find(y);
if (x == y) return false;
if (x > y) swap(x, y);
sz[x] += sz[y];
p[y] = x;
return true;
}
};
void Showball(){
int n,q;
cin>>n>>q;
DSU dsu(n+1);
vector<int> cnt(n+2,1),color(n+2);
iota(color.begin(),color.end(),0);
while(q--){
int op;
cin>>op;
if(op==1){
int x,c;
cin>>x>>c;
int l=dsu.find(x);
int len=dsu.sz[l];
cnt[color[l]]-=len;
color[l]=c;
cnt[color[l]]+=len;
if(color[dsu.find(l-1)]==color[l]) dsu.merge(l-1,l);
if(color[dsu.find(l+len)]==color[l]) dsu.merge(l,l+len);
}else{
int c;
cin>>c;
cout<<cnt[c]<<"\n";
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
//cin>>t;
while(t--){
Showball();
}
return 0;
}
F - Exchange Game 博弈+状压
我们发现数据范围很小,考虑状态压缩。分别存储先手和后手以及桌上的牌型。
然后记忆化搜索即可。如果一个状态的后继状态中存在一个必败态,那么这个状态一定是必胜态。(因为玩家很聪明,一定会走到这个状态),否则当前状态为必败态。
具体实现参考代码及注释。
#include<bits/stdc++.h>
using namespace std;
using i64=long long;
void Showball(){
int n,m,l;
cin>>n>>m>>l;
int len=n+m+l;
vector<int> a(len);
for(int i=0;i<len;i++) cin>>a[i];
vector<vector<int>> dp(4100,vector<int>(4100));
function<int(int,int)> dfs=[&](int x,int y){
if(dp[x][y]) return dp[x][y];
int st=x+y;
for(int i=0;i<len;i++){//枚举桌上牌型
if(st>>i&1) continue;
for(int j=0;j<len;j++){//枚举当前先手牌型
if(!(x>>j&1)) continue;
if(a[j]>a[i]){//可以摸桌上牌
int t=x-(1<<j)+(1<<i);
int tt=dfs(y,t);
if(tt==2) return dp[x][y]=1;
}else{//不能摸桌上牌
int t=x-(1<<j);
int tt=dfs(y,t);
if(tt==2) return dp[x][y]=1;
}
}
}
return dp[x][y]=2;
};
int x=0,y=0;
for(int i=0;i<n;i++) x|=1<<i;
for(int i=n;i<n+m;i++) y|=1<<i;
int ans=dfs(x,y);
cout<<(ans==1?"Takahashi\n":"Aoki\n");
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
//cin>>t;
while(t--){
Showball();
}
return 0;
}
G - Another Shuffle Window 思维+期望+逆序对
先来一道前置例题:CF749E
简要题意:给出一个
思路:考虑每一对
那么如果
反之,产生了
我们只需要枚举区间右端点,然后用树状数组统计大于和小于右端点的下标之和即可算出贡献。
统计逆序对使用树状数组即可。
代码:
#include<bits/stdc++.h>
using namespace std;
using i64=long long;
void Showball(){
int n;
cin>>n;
vector<int> a(n+1);
for(int i=1;i<=n;i++) cin>>a[i];
vector<array<i64,2>> tr(n+1);
auto add=[&](int op,int x,int v){
for(;x<=n;x+=x&-x) tr[x][op]+=v;
};
auto getsum=[&](int op,int x){
i64 ret=0;
for(;x;x-=x&-x) ret+=tr[x][op];
return ret;
};
double q,ans=0;
for(int i=1;i<=n;i++){
q+=getsum(0,n)-getsum(0,a[i]);
add(0,a[i],1);
ans-=(n-i+1)*(getsum(1,n)-getsum(1,a[i]));
ans+=(n-i+1)*(getsum(1,a[i]));
add(1,a[i],i);
}
ans/=n;ans/=(n+1);
cout<<fixed<<setprecision(9)<<q+ans<<"\n";
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
//cin>>t;
while(t--){
Showball();
}
return 0;
}
通过上面这个题,我们就会知道长度为
那么我们去分别考虑每一个长度为
我们发现洗牌中间序列,对三段之间互相形成的逆序对不会有影响。那么我们可以通过算出总的逆序对数和中间段的逆序对数,作差来得到两边区间的逆序对数。除以
前一部分,我们直接使用树状数组类似滑动窗口的维护即可, 中间区间的期望逆序对数量 就可以用上一题的启发了。即为
#include<bits/stdc++.h>
using namespace std;
using i64=long long;
const int mod = 998244353;
void Showball(){
int n,k;
cin>>n>>k;
vector<int> a(n+1);
for(int i=1;i<=n;i++) cin>>a[i];
vector<i64> tr(n+1);
auto add=[&](int x,int v){
for(;x<=n;x+=x&-x) tr[x]+=v;
};
auto getsum=[&](int x){
i64 ret=0;
for(;x;x-=x&-x) ret+=tr[x];
return ret;
};
auto inv=[&](i64 a){
i64 b=mod-2,ret=1;
while(b){
if(b&1) ret=ret*a%mod;
a=a*a%mod;
b>>=1;
}
return ret;
};
i64 sum=0;
for(int i=n;i;i--){
sum+=getsum(a[i]);
add(a[i],1);
}
for(int i=0;i<=n;i++) tr[i]=0;
i64 cur=0;
for(int i=k;i;i--){
cur+=getsum(a[i]);
add(a[i],1);
}
i64 ans=sum-cur;
for(int i=1;i+k<=n;i++){
add(a[i],-1);
cur-=getsum(a[i]);
cur+=getsum(n)-getsum(a[i+k]);
add(a[i+k],1);
ans=(ans+sum-cur)%mod;
}
ans=(ans*inv(n-k+1)%mod+1LL*k*(k-1)%mod*inv(4)%mod)%mod;
cout<<ans<<"\n";
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
//cin>>t;
while(t--){
Showball();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】