ARC145

ARC145

tasks

   表示赛时做出。
   表示赛后已补。
   表示 To be solved

VP

score A B C
72:49 10:45 28:04 62:49
+2 +2

rk:342ed
perf:2075

A

A-AB Palindrome


Difficulty:596

Description

给定长为 n,由 AB 组成的字符串,每次可以选择相邻两位替换成 AB
询问原字符串是否能通过若干次操作变成回文字符串。

Solution

可以发现,如果最后一个字符是 A,就可以从头开始覆盖到最后一位前,即结果为 ABB……BBA 的情况。
同理,如果开头字符为 B,就从后往前覆盖,形如 BAA……AAB
长度为 2 的字符串要特判。

code
/*******************************
| Author:  A.I.skeleton
| Problem: A - AB Palindrome
| Contest: AtCoder - AtCoder Regular Contest 145
| URL:     https://atcoder.jp/contests/arc145/tasks/arc145_a
| When:    2022-10-20 08:58:11
| 
| Memory:  1024 MB
| Time:    2000 ms
*******************************/
#include <bits/stdc++.h>
using namespace std;
#define FST ios::sync_with_stdio(0);cin.tie(0);

#define int long long

const int N=2e6+100,INF=1e18;
char s[N];int n;
signed main(){
  FST;cin>>n>>(s+1);
  if(n==2) return cout<<(s[1]^s[2]?"No":"Yes"),0;
  cout<<((s[n]=='A'||s[1]=='B')?"Yes":"No");
}

B

B-AB Game


Difficulty:767

Description

取石子游戏,先手每次取 A 的倍数块,后手每次取 B 的倍数块,求问先手胜利数。

Solution

先考虑几个特殊情况:

  1. 如果 a>n,显然答案为 0
  2. 如果 ab,此时答案为 max(na+1,0),因为 a>n 是必败态。

在此基础上,尝试证明:先手尽可能多的取走石子是最优策略。

proof

因为已经排除了 ab 的情况,所以此时 b<a,假设先手没有尽可能多取石子,那么剩下的石子数会 a>b
后手显然可以尽可能多的取走石子,使得剩下石子数 <b,此时为先手必败态。
所以,先手应尽量多的取走石子,否则必然为必败态。

然后不难得到,计算式为 i=1n[imoda<b]

code
/*******************************
| Author:  A.I.skeleton
| Problem: B - AB Game
| Contest: AtCoder - AtCoder Regular Contest 145
| URL:     https://atcoder.jp/contests/arc145/tasks/arc145_b
| When:    2022-10-20 09:08:27
| 
| Memory:  1024 MB
| Time:    2000 ms
*******************************/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define FST ios::sync_with_stdio(0);cin.tie(0);

#define int long long

int n,a,b,ans;
signed main(){
  FST;cin>>n>>a>>b;if(n<a) return cout<<0,0;
  if(a<=b) return cout<<max(n-a+1,0ll),0;n++;
  ans=max(n/a-1,0ll)*b+min(b,n%a);cout<<ans;
}

C

C-Split and Maximize


Difficulty:1697

Description

给定 n,输 2n 的所有排列中,将其分成两个大小为 n 的子序列 A,B,使得 i=1nAiBi 为最大值的方案数。

Solution

首先,显然最优的构造方案只有可能形如:(1,2),(3,4),,(2n1,2n)
即:对于 i[1,n]2i1 必须与 2i 配对。
如果把所有奇数看做左括号,偶数看做右括号,某个序列可能产生构造方案就是此序列转化的括号序列合法,也就是卡特兰数:1n+1(2nn)

因为左括号可以随意排列,所以乘上 n!
因为不一定所有奇数看成左括号,同理会产生 2n 种不同的情况。

所以最后的总方案数是: 2nn!1n+1(2nn)=2nAn12n

code
/*******************************
| Author:  A.I.skeleton
| Problem: C - Split and Maximize
| Contest: AtCoder - AtCoder Regular Contest 145
| URL:     https://atcoder.jp/contests/arc145/tasks/arc145_c
| When:    2022-10-20 09:23:49
| 
| Memory:  1024 MB
| Time:    2000 ms
*******************************/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
#define L(i,j,k) for(int (i)=(j);i<=(k);(i)++)
#define R(i,j,k) for(int (i)=(j);i>=(k);(i)--)
#define FST ios::sync_with_stdio(0);cin.tie(0);

const int P=998244353;
int O(int x){return x<0?(x+=P):x<P?x:(x-=P);}
template<class T>
T ksm(T a,ll b){T s=1;for(;b;b>>=1,a*=a) if(b&1) s*=a;return s;}
struct Z{
  int x;Z(int x=0):x(O(x)){}Z(ll x):x(O(x%P)){}
  int val()const{return x;}Z operator-()const{return Z(O(P-x));}
  Z inv()const{assert(x!=0);return ksm(*this,P-2);}
  Z&operator/=(const Z&r){return*this*=r.inv();}
  Z&operator+=(const Z&r){x=O(x+r.x);return*this;}
  Z&operator-=(const Z&r){x=O(x-r.x);return*this;}
  Z&operator*=(const Z&r){x=(ll)(x)*r.x%P;return*this;}
  friend Z operator*(const Z&l,const Z&r){Z s=l;s*=r;return s;}
  friend Z operator+(const Z&l,const Z&r){Z s=l;s+=r;return s;}
  friend Z operator-(const Z&l,const Z&r){Z s=l;s-=r;return s;}
  friend Z operator/(const Z&l,const Z&r){Z s=l;s/=r;return s;}
  friend ostream&operator<<(ostream&os,const Z&a){return os<<a.val();}
  friend istream&operator>>(istream&is,Z&a){ll v;is>>v;a=Z(v);return is;}
};namespace math{
  Z jc[1000100],ijc[1000100];
  void init(int x){
    jc[0]=1;L(i,1,x) jc[i]=jc[i-1]*i;
    ijc[x]=jc[x].inv();R(i,x,1) ijc[i-1]=ijc[i]*i;
  }Z C(int n,int m){return jc[n]*ijc[n-m]*ijc[m];}
  Z A(int n,int m){/*cout<<ijc[n-m]<<endl;*/return jc[n]*ijc[n-m];}
}using namespace math;

ll qmul(ll a,ll b,ll p){
  ll c=(ld)a/p*b;
  ll res=(ull)a*b-(ull)c*p;
  return (res+p)%p;
}ll power(ll a,ll b,ll p){
  ll s=1;while(b){
    if(b&1) s=qmul(s,a,p);
    a=qmul(a,a,p);b>>=1;
  }return s;
}

#define int long long

signed main(){
  FST;int n;Z ans;cin>>n;init(n*2);
  cout<<(ans=power(2,n,P)*A(n*2,n-1));
}

当然,在赛时,完全可以先写个爆搜把前几个答案打出来,然后丢到 OEIS 上。
然后把 A152029 的通项公式套回来,就能直接无脑解决这个问题。

D

D-Non Arithmetic Progression Set

人类智慧题。


Difficulty:2297

Description

给定 n,m,构造一个 n 个数组成的集合,其 iS=m,对于集合内任意递增的数 x,y,z,有 yxzy

Solution 1

首先只关注最后一个限制条件。
yxzy2x+y

考虑三进制下的数
让集合 S 中所有数在三进制下的最后一位都为 0/1
这样因为 x<z 那么 (x+z)(3) 中必然有一位是 1
(2y)(3) 的每一位都只能是 0/2,这样就保证了该限制条件。

继续看 iS=m 的限制条件。
先建立一个满足上述条件的集合 S,设 iS=x
集合中总共有 n 个数,所有数减去某个数相当于减去这个数乘 n
所以要把 |mx| 变成 n 的倍数。
因为 |mx| 与最近的 n 的倍数的差值不会超过 n,考虑将 S 中所有数的三进制下最后一位都设为 0,在调整时改变某一些部分,使得其最后一位变为 1,这样就同时满足了两个性质。

按照上述过程模拟即可,代码难度不大,主要偏思维。

code
/*******************************
| Author:  A.I.skeleton
| Problem: D - Non Arithmetic Progression Set
| Contest: AtCoder - AtCoder Regular Contest 145
| URL:     https://atcoder.jp/contests/arc145/tasks/arc145_d
| When:    2022-10-20 10:06:44
| 
| Memory:  1024 MB
| Time:    2000 ms
*******************************/
#include <bits/stdc++.h>
using namespace std;
#define L(i,j,k) for(int (i)=(j);i<=(k);(i)++)
#define FST ios::sync_with_stdio(0);cin.tie(0);
const int N=2e6+100;
int n,m,del,a[N];
signed main(){
  FST;cin>>n>>m;
  L(i,1,n){
    int c=0,g=3;
    for(int j=0;j<14;j++,g*=3)
      if((i&(1<<j))) c+=g;
    m-=(a[i]=c);
  }del=(m<0?m%n+n:(m%n));
  L(i,1,del) a[i]++;del=(m-del)/n;
  L(i,1,n) cout<<a[i]+del<<' ';
}

Solution 2

总体思路类似,也是先构造出满足最后一个限制条件的集合 S,再修改其中某些值使得其 m 的差为 n 的倍数,然后修改整个数组,但是不依赖于三进制的人类智慧。

f(i) 表示大小为 i 的满足最后一个限制条件的集合 S
保证: {f(1)={0}f(2n)=f(n)(f(n)+2maxf(n)+1)

可知这样的集合是满足限制的。
然后调整其中最大的那部分值(从后往前),使差值为 n 的倍数。
修改整个数组,输出即可。

code
/*******************************
| Author:  A.I.skeleton
| Problem: D - Non Arithmetic Progression Set
| Contest: AtCoder - AtCoder Regular Contest 145
| URL:     https://atcoder.jp/contests/arc145/tasks/arc145_d
| When:    2022-10-20 10:06:44
| 
| Memory:  1024 MB
| Time:    2000 ms
*******************************/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
#define vi vector<int>
#define all(x) (x).begin(),(x).end()
#define L(i,j,k) for(int (i)=(j);i<=(k);(i)++)
#define FST ios::sync_with_stdio(0);cin.tie(0);
int n,m;
vi work(int x){
  if(x==1) return {0};
  int m=(x+1)/2;auto g=work(m);
  L(i,0,m-1) g.pb(g[i]+g[m-1]*2+2);
  g.resize(x);return g;
}signed main(){
  FST;cin>>n>>m;auto a=work(n);
  int cnt=accumulate(all(a),0ll);
  m-=cnt;int t=m/n;m-=t*n;
  if(m<0) t--,m+=n;
  for(int &i:a) i+=t;
  L(i,n-m,n-1) a[i]++;
  for(int i:a) cout<<i<<' ';
}

E

E-Adjacent XOR


Difficulty:3581

F

F-Modulo Sum of Increasing Sequences


Difficulty:3943

posted @   AIskeleton  阅读(84)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示