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;
}
posted @ 2024-05-11 22:10  No_Play_Yes_Splay  阅读(355)  评论(0编辑  收藏  举报