首页 > 其他分享 >Atcoder Beginner Contest 339 解题报告

Atcoder Beginner Contest 339 解题报告

时间:2024-02-03 22:33:29浏览次数:26  
标签:Atcoder 339 cout Beginner int max void tr Theta

Atcoder Beginner Contest 339

场评:B>C,D>E,F>G,中国选手最擅长的 G,集体上分。

A - TLD

Simulate.

string s;
void Solve()
{
	char c;
	while(cin>>c)
	{
		if(c=='.')s="";
		else s+=c;
	}
	cout<<s;
}

B - Langton's Takahashi

Simulate.

const int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
int n,m,k;
bool f[100][100];
void Solve()
{
	cin>>n>>m>>k;
	int cx=0,cy=0;unsigned d=0;
	while(k--)
	{
		if(f[cx][cy])d=(d-1)&3;
		else d=(d+1)&3;
		f[cx][cy]^=1;
		cx=(cx+dx[d]+n)%n,cy=(cy+dy[d]+m)%m;
	}
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<m;j++)cout<<(f[i][j]?'#':'.');
		cout<<endl;
	}
}

C - Perfect Bus

从后往前累加然后取 \(\max\) 即可。时间 \(\Theta(n)\)。

int n,a[200005];
ll mx,cur;
void Solve()
{
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=n;i;i--)
		mx=max(mx,cur+=a[i]);
	cout<<mx;
}

D - Synchronized Players

设两人位置分别为 \((x_1,y_1),(x_2,y_2)\),则以 \((x_1,y_1,x_2,y_2)\) 为状态 BFS 即可。

时间 \(\Theta(n^4)\)。

const int N=60,dx[4]={-1,0,0,1},dy[4]={0,-1,1,0};
int n;
string s[N];
int f[N][N][N][N];
int p1x=-1,p1y,p2x,p2y;
void Solve()
{
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>s[i];
		for(int j=0;j<n;j++)
			if(s[i][j]=='P')
			{
				if(~p1x)p2x=i,p2y=j;
				else p1x=i,p1y=j;
			}
	}
	memset(f,-1,sizeof(f));
	queue<array<int,4>>q;
	q.push({p1x,p1y,p2x,p2y});
	f[p1x][p1y][p2x][p2y]=0;
	while(nempty(q))
	{
		auto x=q.front();q.pop();
		int x1=x[0],y1=x[1],x2=x[2],y2=x[3];
		if(x1==x2&&y1==y2)return (void)(cout<<f[x1][y1][x2][y2]);
		for(int i=0;i<4;i++)
		{
			int nx1=x1+dx[i],ny1=y1+dy[i],nx2=x2+dx[i],ny2=y2+dy[i];
			if(nx1<0||ny1<0||nx1>=n||ny1>=n||s[nx1][ny1]=='#')
				nx1=x1,ny1=y1;
			if(nx2<0||ny2<0||nx2>=n||ny2>=n||s[nx2][ny2]=='#')
				nx2=x2,ny2=y2;
			if(!~f[nx1][ny1][nx2][ny2])
				f[nx1][ny1][nx2][ny2]=f[x1][y1][x2][y2]+1,
				q.push({nx1,ny1,nx2,ny2});
		}
	}
	cout<<-1;
}

E - Smooth Subsequence

令 \(dp_i\) 表示某时刻最后一个数为 \(i\) 时的最大长度。

加入一个数 \(x\) 时,则令

\[dp_x\gets1+\max_{i=x-d}^{x+d}(dp_i) \]

即可。单点改区间 \(\max\),线段树解决。时间 \(\Theta(n\log n)\)。

const int N=500005,P=N-5;
int n,d;
struct SGT
{
	int tr[1<<20];
#define lid (id<<1)
#define rid (lid|1)
#define mid (l+r>>1)
#define rmd (mid+1)
	SGT(){memset(tr,0,sizeof(tr));}
	void pushup(int id){tr[id]=max(tr[lid],tr[rid]);}
	void modify(int pos,int val,int l=1,int r=P,int id=1)
	{
		if(l==r)return (void)(tr[id]=val);
		if(pos<=mid)modify(pos,val,l,mid,lid);
		else modify(pos,val,rmd,r,rid);
		pushup(id);
	}
	int mx(int ql,int qr,int l=1,int r=P,int id=1)
	{
		if(ql==l&&qr==r)return tr[id];
		int rs=0;
		if(ql<=mid)rs=max(rs,mx(ql,min(qr,mid),l,mid,lid));
		if(qr>=rmd)rs=max(rs,mx(max(ql,rmd),qr,rmd,r,rid));
		return rs;
	}
}t;
void Solve()
{
	cin>>n>>d;
	for(int i=1,x;i<=n;i++)
	{
		cin>>x;
		t.modify(x,1+t.mx(max(1,x-d),min(P,x+d)));
	}
	cout<<t.mx(1,P);
}

F - Product Equality

先想如果 \(a_i\le10^9\) 怎么做。直接枚举 \(i,j\) 然后算出 \(k\) 共有几个即可。时间 \(\Theta(n^2)\)。

然后想 \(a_i<10^{1000}=10^L\) 时怎么做。此时做一次乘法都要 \(\Theta(L\log L)\),而且 ABC 的 F 是基本不会考 FFT 的,直接乘必 T 无疑。

考虑 hash,随便取几个模数 \(p\)(假设为 \(s\) 个),那么可以很轻松的算出每个 \(a_i\) 对 \(p\) 取模后的值。然后判一下模意义下成立的三元组,取个交集即可。

错误率约为 \(\frac1{\prod p}\),时间 \(\Theta(n(n+L)s)\)。

下列代码取了 4 个固定模数和 6 个随机模数。

mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
uniform_int_distribution<int>f(1000000000,2000000000);
const int N=1005;
ll md[10]={998244353,1000000007,1000000009,2147483647};
int n;
array<ll,10> v[N];
map<array<ll,10>,int>st;
void Solve()
{
	for(int i=4;i<=9;i++)
		md[i]=f(rnd);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		string s;cin>>s;
		for(char j:s)
			for(int k=0;k<10;k++)
				v[i][k]=(v[i][k]*10+j-'0')%md[k];
		st[v[i]]++;
	}
	int cnt=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
		{
			array<ll,10>c;
			for(int k=0;k<10;k++)c[k]=v[i][k]*v[j][k]%md[k];
			cnt+=st[c];
		}
	cout<<cnt;
}

G - Smaller Sum

一眼扫描线秒了,但是一看强制在线。/doge

(主席树也可以,而且更优秀(\(\Theta(n\log^2 n)\)),这是赛时做法。)

考虑对序列分块,块长为 \(B\),令 \(val_i\) 为前 \(i\) 个块中的所有元素从小到大排序后的结果。

预处理 \(val\) 时,先给序列排序,然后从小到大对每个元素,把其所在块及之后的块全部 push_back 这个元素即可。此部分时间 \(\Theta(n\cdot\frac nB)=\Theta(\frac{n^2}B)\)。

先把询问差分成前缀中 \(\le x\) 的和。

然后前面的整块可以直接 upper_bound 求出 \(\le x\) 的分界,然后开始时预处理前缀和即可求出其和。后面的散块直接暴力 check 是否 \(\le x\) 即可。此部分时间 \(\Theta(\log\frac nB+B)\)。

总时间复杂度 \(\Theta(\frac{n^2}B+qB+q\log\frac nB)\)。当 \(n,q\) 同阶时取 \(B=\sqrt n\) 即可做到 \(\Theta(n\sqrt n)\) 时空复杂度。

注意空间消耗别重蹈我 PKUWC2024D2T3 的覆辙(谁能想到几天前才被卡分块的我几天后又来写分块了呢)

const int N=200005,B=450;
int n,q,a[N],ps[N];
VI vals[B];
vector<ll> sums[B];
int K(int x){return (x+B-1)/B;}
ll get(int r,int x)
{
	int k=K(r+1);
	ll res=0;
	int po=upper_bound(ALL(vals[k-1]),x)-vals[k-1].begin()-1;
	if(~po)res+=sums[k-1][po];
	for(int i=(k-1)*B+1;i<=r;i++)
		res+=a[i]*(a[i]<=x);
	return res;
}
void Solve()
{
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	iota(ps+1,ps+n+1,1);
	sort(ps+1,ps+n+1,[&](int x,int y){return a[x]<a[y];});
	for(int i=1;i<=n;i++)
	{
		int p=ps[i];
		for(int j=K(p);j<B;j++)vals[j].PB(a[p]);
	}
	for(int i=1;i<B;i++)
	{
		ll sum=0;
		for(int j:vals[i])sums[i].PB(sum+=j);
	}
	cin>>q;
	ll ans=0;
	while(q--)
	{
		ll l,r,x;
		cin>>l>>r>>x;
		l^=ans,r^=ans,x^=ans;
		cout<<(ans=get(r,x)-get(l-1,x))<<endl;
	}

标签:Atcoder,339,cout,Beginner,int,max,void,tr,Theta
From: https://www.cnblogs.com/No-play-Yes-splay/p/18005329/abc339-solution

相关文章

  • ABC339
    题解不应该流露出太多感情,对吧。E建议评黄。首先我们可以想到暴力dp。定义\(dp_i\)为以\(a_i\)为结尾满足题目意思的最长序列的长度。很明显,时间复杂度为\(O(n^2)\)不可通过本题。我们发现一个序列以\(a_i\)为结尾,那么上一位绝对是以\(a_i-k\)到\(a_i+k\)中的......
  • AtCoder Beginner Contest 339
    A-TLD(abc339A)题目大意给一个网址,问它的后缀是多少。解题思路找到最后的'.'的位置,然后输出后面的字符串即可。python可以一行。神奇的代码print(input().split('.')[-1])B-Langton'sTakahashi(abc339B)题目大意二维网格,上下左右相连,左上原点。初始全部为......
  • ABC339 题解
    AK了。A-TLD给出一个字符串\(s\),输出最后一个.后面的内容。\(|s|\le100\)。\(\text{2sec/1024MB}\)。按照题意模拟即可,时空复杂度均为\(\mathcal{O}(|s|)\)。ACCodeB-Langton'sTakahashi给出\(H\timesW\)的网格。初始你在\((1,1)\),方向......
  • ABC 339 破防记
    我是沙波。嘿!A好难。Code#include<bits/stdc++.h>usingnamespacestd;usingll=longlong;intmain(){ ios::sync_with_stdio(false); cin.tie(0); strings; cin>>s; stringt=s; reverse(t.begin(),t.end()); stringx; for(inti=0;i<t.s......
  • ABC339 题解(A~G)
    A从后向前找到第一个.就行了。B按照题意模拟,设当前位置\(x,y\)移动方向\(dx,dy\)。那么下一步为\((x+dx,y+dy)\)设新的移动方向为\(dx',dy'\)如果顺时针旋转,则有\(dy'\gets-dx,dx'\getsdy\);如果逆时针,则有\(dx'\gets-dy,dy'\getsdx\)。C鉴定为除A以外......
  • AtCoder Beginner Contest 333
    ABC334总结https://atcoder.jp/contests/abc333A-ThreeThrees翻译输入一个正整数\(n\),输出\(n\)遍这个正整数。\(1\len\le9\)。分析没啥好说的,直接输出就好了。code#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;intn;intmain()......
  • E - Revenge of "The Salary of AtCoder Inc."
    E-Revengeof"TheSalaryofAtCoderInc."ProblemStatementAoki,anemployeeatAtCoderInc.,hashissalaryforthismonthdeterminedbyaninteger$N$andasequence$A$oflength$N$asfollows.First,heisgivenan$N$-sideddie(dice)th......
  • AtCoder Beginner Contest 330 ABCDE
    AtCoderBeginnerContest330ABCDEA-CountingPasses签到题,不多说。//AConemoretimes//nndbk#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;constintmod=1e9+7;constintN=2e5+10;intmain(){ios::sync_with_stdi......
  • AtCoder Beginner Contest 336
    ABC336总结AtCoderBeginnerContest336A-LongLoong翻译给定一个数\(n\),请输出一个由一个L、\(n\)个o、一个n和一个g组成的字符串(区分大小写)。分析按题意模拟即可。code#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;constintN=1......
  • 洛谷题单指南-暴力枚举-P3392 涂国旗
    原题链接:https://www.luogu.com.cn/problem/P3392题意解读:此题枚举白、蓝、红所有可能的行数组合,依次逐行判断每个方格,是否需要染色,计算最少的染色次数即可。解题思路:总行数是n,先考虑白色,第一行必是白色,最后一行必是红色,至少有一行蓝色,因此白色行数的范围是1~n-2再考虑蓝......