AtCoder Beginner Contest 353 解题报告
AtCoder Beginner Contest 353
唐氏场。为啥 G 比 F 多过了一坨人啊。
A - Buildings
Simulate.
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false),cin.tie(nullptr);
// int _;cin>>_;while(_--)
int n,fir,x;
cin>>n>>fir;
for(int i=2;i<=n;i++)
{
cin>>x;
if(x>fir)return cout<<i,0;
}
cout<<-1;
return 0;
}
B - AtCoder Amusement Park
Simulate.
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false),cin.tie(nullptr);
// int _;cin>>_;while(_--)
int n,k,x,cur=0,ans=1;
cin>>n>>k;
while(n--)cin>>x,(cur+x<=k?cur+=x:(cur=x,ans++));
cout<<ans;
return 0;
}
C - Sigma Problem
倒着扫,先加总和,然后 \(\bmod\;10^8\) 就减去 \(10^8\times\#(y\ge10^8-x)\) 就行了,树状数组维护即可。由于我懒所以没离散化。以下代码 \(\Theta(P+n\log P)\),其中 \(P=10^8\),但可以优化到 \(\Theta(n\log n)\)。
#include<bits/stdc++.h>
using namespace std;
const int N=300005,P=1e8;
int n,a[N];
int c[P+5];
void add(int x,int v){while(x<=P)c[x]+=v,x+=x&-x;}
int get(int x){int r=0;while(x)r+=c[x],x^=x&-x;return r;}
int main()
{
ios::sync_with_stdio(false),cin.tie(nullptr);
// int _;cin>>_;while(_--)
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
ll sm=0,ans=0;
for(int i=n;i;i--)
{
ans+=sm+1ll*a[i]*(n-i)-1ll*(n-i-get(P-a[i]-1))*P;
add(a[i],1),sm+=a[i];
}
cout<<ans;
return 0;
}
D - Another Sigma Problem
统计每个数贡献即可。\(\Theta(n\log_BV)\),其中 \(V\) 为值域,\(B=10\)。
#include<bits/stdc++.h>
using namespace std;
const int N=200005;
int n,a[N];
ll totw,w[N];
int main()
{
ios::sync_with_stdio(false),cin.tie(nullptr);
// int _;cin>>_;while(_--)
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
int t=a[i];
w[i]=1;
while(t)w[i]*=10,t/=10;
totw+=w[i];
}
ll ans=0;
for(int i=1;i<=n;i++)
ans=(ans+1ll*a[i]*((i-1+(totw-=w[i]))%998244353))%998244353;
cout<<ans;
return 0;
}
E - Yet Another Sigma Problem
转换为求
\[\begin{aligned}&\sum_{i=1}^n\sum_{j=i+1}^n\sum_{k=1}^\infty[\operatorname{LCP}(s_i,s_j)\ge k]\\=&\sum_{k=1}^\infty\sum_{i=1}^n\sum_{j=i+1}^n[\operatorname{LCP}(s_i,s_j)\ge k]\end{aligned},
\]
然后就可以直接 Trie 维护。\(\Theta((\sum|s_i|)|\Sigma|)\),其中 \(|\Sigma|=26\)。
#include<bits/stdc++.h>
using namespace std;
int n;
ll ans;
string s[300005];
struct trie
{
int cnt,son[26];
}tr[300005];int tot;
int main()
{
ios::sync_with_stdio(false),cin.tie(nullptr);
// int _;cin>>_;while(_--)
cin>>n;
while(n--)
{
string s;cin>>s;
int cur=0;
for(char i:s)
{
i-='a';
if(!tr[cur].son[i])tr[cur].son[i]=++tot;
cur=tr[cur].son[i],tr[cur].cnt++;
}
}
for(int i=1;i<=tot;i++)ans+=tr[i].cnt*(tr[i].cnt-1ll)/2;
cout<<ans;
return 0;
}
F - Tile Distance
\[\Huge\text{19:21 过居然一血????}
\]
有点恶心的分讨。
首先判掉直接曼哈顿距离走过去的 case。
否则可以发现,一定是从 \(S\) 径直走到一个大格子,通过若干大格子,最后径直走到 \(T\)。
可以发现,我们最少要花费 \(2\) 的代价,从一个大格子走到(对角)相邻的大格子。
在考虑其他的移动方式:从一个大格子走到隔着一堆小格子的大格子,需要花费 \(k+1\) 的代价。当且仅当 \(k\le 2\) 时是较优的。
那么枚举一下 \(S,T\) 相邻的大格子,然后算一下距离即可,这部分是简单的。
时间复杂度 \(\Theta(1)\)。
#include<bits/stdc++.h>
using namespace std;
ll k,sx,sy,tx,ty;
vector<pair<pair<ll,ll>,ll>>tg1,tg2;
ll dis(pair<ll,ll>x,pair<ll,ll>y)
{
ll dx=abs(x.fi-y.fi),dy=abs(x.se-y.se);
if(k==2)return 2*min(dx,dy)+3*abs(dx-dy)/2;
return 2*max(dx,dy);
}
int main()
{
ios::sync_with_stdio(false),cin.tie(nullptr);
// int _;cin>>_;while(_--)
cin>>k>>sx>>sy>>tx>>ty;
if(k==1)return cout<<abs(sx-tx)+abs(sy-ty),0;
if((sx/k+sy/k)&1)tg1.PB(MP(sx/k,sy/k),0);
else
{
tg1.PB(MP(sx/k-1,sy/k),sx%k+1);
tg1.PB(MP(sx/k+1,sy/k),k-sx%k);
tg1.PB(MP(sx/k,sy/k-1),sy%k+1);
tg1.PB(MP(sx/k,sy/k+1),k-sy%k);
}
if((tx/k+ty/k)&1)tg2.PB(MP(tx/k,ty/k),0);
else
{
tg2.PB(MP(tx/k-1,ty/k),tx%k+1);
tg2.PB(MP(tx/k+1,ty/k),k-tx%k);
tg2.PB(MP(tx/k,ty/k-1),ty%k+1);
tg2.PB(MP(tx/k,ty/k+1),k-ty%k);
}
ll ans=abs(sx-tx)+abs(sy-ty);
for(auto i:tg1)
for(auto j:tg2)
ans=min(ans,dis(i.fi,j.fi)+i.se+j.se);
cout<<ans;
return 0;
}
G - Merchant Takahashi
典中典。
首先 \(\Theta(n^2)\) 是 sb 的:
\[dp_i=\max_{j=0}^{i-1}\{dp_j-C|t_i-t_j|\}+p_i.
\]
绝对值很烦,考虑分段,WLOG 我们假设 \(t_i\ge t_j\),反之同理。
\[dp_i=\max_{\substack{0\le j<i\\t_j\le t_i}}\{dp_j+Ct_j\}+p_i-Ct_i.
\]
所以只需维护(位置上的)单点改,前缀 \(\max\) 即可。用 std::set
或线段树维护,\(\Theta(n\log n)\)。
#include<bits/stdc++.h>
using namespace std;
const int N=200005;
int n,C,m;
set<pair<int,ll>>lef,rig;
int main()
{
ios::sync_with_stdio(false),cin.tie(nullptr);
// int _;cin>>_;while(_--)
cin>>n>>C>>m;
lef.emplace(1,C),rig.emplace(1,-C);
ll ans=0;
for(int i=1;i<=m;i++)
{
int x;ll y;
cin>>x>>y;
ll dp=LLONG_MIN;
auto it=lef.upper_bound(MP(x,LLONG_MAX));
if(it!=lef.begin())dp=prev(it)->se-1ll*x*C;
it=rig.lower_bound(MP(x,LLONG_MIN));
if(it!=rig.end())dp=max(dp,it->se+1ll*x*C);
ans=max(ans,dp+=y);
it=lef.upper_bound(MP(x,LLONG_MIN));
if(it==lef.begin()||dp+1ll*x*C>prev(it)->se)
{
while(it!=lef.end()&&it->se<=dp+1ll*x*C)
it=lef.erase(it);
lef.emplace(x,dp+1ll*x*C);
}
it=rig.lower_bound(MP(x,LLONG_MAX));
if(it==rig.end()||dp-1ll*x*C>it->se)
{
while(it!=rig.begin()&&prev(it)->se<=dp-1ll*x*C)
if(prev(it)!=rig.begin())it=rig.erase(prev(it));
else {rig.erase(prev(it));break;}
rig.emplace(x,dp-1ll*x*C);
}
}
cout<<ans;
return 0;
}