[题解]AtCoder Beginner Contest 425(ABC425) A~F
A - Sigma Cubes
\((-1)^i\) 在 \(i\) 为奇数时为 \(-1\),偶数时为 \(1\)。按题意模拟即可。
时间复杂度 \(O(n)\)。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,ans;
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
if(i&1) ans-=i*i*i;
else ans+=i*i*i;
}
cout<<ans<<"\n";
return 0;
}
B - Find Permutation 2
初始定义集合 \(S=\{1,2,\dots,n\}\)。
将 \(A\) 中非 \(-1\) 的值从 \(S\) 中删掉,剩下的元素按任意顺序填入 \(-1\) 处即可。
时间复杂度 \(O(n\log n)\) 或 \(O(n)\)。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=15;
int n,a[N];
set<int> s;
signed main(){
cin>>n;
for(int i=1;i<=n;i++) s.insert(i);
for(int i=1;i<=n;i++){
cin>>a[i];
if(~a[i]){
if(s.count(a[i])){
s.erase(a[i]);
}else{
cout<<"No\n";
return 0;
}
}
}
cout<<"Yes\n";
for(int i=1;i<=n;i++){
if(~a[i]) cout<<a[i]<<" ";
else{
cout<<*(s.begin())<<" ";
s.erase(s.begin());
}
}
return 0;
}
C - Rotate and Sum Query
下文规定下标从 \(0\) 开始。
容易发现,若旋转操作总共进行了 \(k\) 次,则 \([l,r]\) 的查询相当于原数组中 \([(l+k)\bmod n,(r+k)\bmod n]=[L,R]\) 的区间和。
特别地,若 \(L>R\),意味着实际上答案是 \([L,N]+[0,R]\)。
时间复杂度 \(O(n+q)\)。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5;
int n,q,a[N],o;
inline int sum(int l,int r){
if(!l) return a[r];
return a[r]-a[l-1];
}
signed main(){
cin>>n>>q;
for(int i=0;i<n;i++){
cin>>a[i];
if(i) a[i]+=a[i-1];
}
int op,x,y;
while(q--){
cin>>op;
if(op==1){
cin>>x;
o+=x;
}else{
cin>>x>>y;
x+=n-1,y+=n-1;
x=(x+o)%n;
y=(y+o)%n;
if(x<=y){
cout<<sum(x,y)<<"\n";
}else cout<<sum(x,n-1)+sum(0,y)<<"\n";
}
}
return 0;
}
也可以用官方题解的方法,将原数组复制一份放在后面,避免拆段。
D - Ulam-Warburton Automaton
BFS 即可。
需要注意的是,每一轮的所有变化是同时进行的。所以不能搜到一个需要入队元素就将它的访问情况设为 #,而是应该将当前轮所有需要入队的元素存起来,等该轮结束后一并设为 #。
时间复杂度 \(O(nm)\)。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
int n,m,dx[4]{-1,0,1,0},dy[4]{0,1,0,-1},ans,pt;
struct Node{int tim,x,y;};
queue<Node> q;
string s[N];
inline int deg(int x,int y){
return (s[x+1][y]=='#')+(s[x-1][y]=='#')+(s[x][y+1]=='#')+(s[x][y-1]=='#');
}
vector<Node> tmp;
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>s[i],s[i]=' '+s[i]+' ';
for(int j=1;j<=m;j++){
if(s[i][j]=='#'){
q.push({0,i,j});
}
}
}
s[0].resize(m+2,' ');
s[n+1].resize(m+2,' ');
while(!q.empty()){
tmp.clear();
while(!q.empty()){
Node t=q.front();
if(t.tim!=pt){
pt=t.tim;
break;
}
q.pop();
int x=t.x,y=t.y,tim=t.tim,xx,yy;
for(int i=0;i<4;i++){
xx=x+dx[i],yy=y+dy[i];
if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&s[xx][yy]!='#'&°(xx,yy)==1){
tmp.emplace_back(Node{tim+1,xx,yy});
}
}
}
for(Node i:tmp){
s[i.x][i.y]='#';
q.push(i);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
ans+=(s[i][j]=='#');
}
}
cout<<ans<<"\n";
return 0;
}
E - Count Sequences 2
多重集合排列板子,答案即为:
但我们发现,此题中的模数并非质数,所以可能找不到乘法拟元。
考虑对 \(C\) 进行质因数分解,从而进行约分。
具体来说,在欧拉筛的过程中记录下 \(i\) 的最小质因数 \(mn_i\)。从大到小遍历每一个 \(i\),将它的指数分配给 \(mn_i\) 和 \(\frac{i}{mn_i}\),直到只有质数剩余即可。
时间复杂度 \(O(T\sum C_i)\approx 5\times 10^8\),不过跑不满,可以通过。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e5+5,C=5e3+5;
int n,p[N],mn[N],idx,t,m,a[C],d[C],c[N];
int qp(int a,int n){
int f=1;
while(n){
if(n&1) f=f*a%m;
a=a*a%m,n>>=1;
}
return f;
}
void init(int n){
for(int i=2;i<=n;i++){
if(!mn[i]) p[++idx]=mn[i]=i;
for(int j=1;j<=idx&&p[j]*i<=n;j++){
mn[i*p[j]]=p[j];
if(i%p[j]==0) break;
}
}
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>t>>m;
init(N-1);
while(t--){
cin>>n;
int sum=0,ans=1;
for(int i=1;i<=n;i++) cin>>c[i],sum+=c[i];
d[sum+1]=0;for(int i=2;i<sum;i++) d[i]=0;
d[sum]=1;//分子
for(int i=1;i<=n;i++) d[c[i]]--;//分母
for(int i=sum;i>1;i--) d[i]+=d[i+1];//后缀和还原回原指数
for(int i=sum;i>1;i--){//约分
if(mn[i]!=i) d[mn[i]]+=d[i],d[i/mn[i]]+=d[i];
}
for(int i=sum;i>1;i--){
if(mn[i]==i) ans=ans*qp(i,d[i])%m;
}
cout<<ans<<"\n";
}
return 0;
}
官方题解给的思路是将上式进行拆分:
通过 \(O((\sum C_i)^2)\) 的递推预处理组合数,可以做到单个样例 \(O(n)\)。
时间复杂度 \(O((\sum C_i)^2+\sum n)\approx 2.5\times 10^7\)。
F - Inserting Process
\(n\) 只有 \(22\),考虑状压 DP。
每种可能出现的字符串,都可以表示为一个长度为 \(n\) 的二进制状态。其中,第 \(i\) 位为 \(1\) 表示 \(s_i\) 未被删除。
则 \(f[2^n-1]=1\) 为初状态,\(f[0]\) 为答案。
转移时,需要注意 \(s\) 中连续相同段的问题。比如 aaa 这个串,011 和 101 两个状态本质是相同的。
所以我们额外规定,删除字符时,只能选择当前段最左侧尚未被删除的字符。
时间复杂度 \(O(2^n\times n)\)。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=22,P=998244353;
int f[1<<N],n,t;
string s;
signed main(){
cin>>n>>s;
f[t=(1<<n)-1]=1;
for(int i=t;~i;i--){
int pre=-1;
for(int j=0;j<n;j++){
if((i>>j)&1){
if(s[j]!=pre){
(f[i^(1<<j)]+=f[i])%=P;
pre=s[j];
}
}
}
}
cout<<f[0]<<"\n";
return 0;
}
浙公网安备 33010602011771号