第五届图灵杯

中级组

T1

我们考虑向后转移,类似 \(dp\)

维护两个等差数列的公差,末项,即可知道等差数列的下一个数

我们考虑爆搜

一个数要么放到第一个序列,要么放到第二个序列

我们贪心,能放到原来的序列就不要新开序列

新序列就算去掉了开头也是等差序列,所以直接放在第一个序列就可以

然后直接爆搜分情况讨论

\(O(2^n \to n)\)

const int N=5e5+10;
int n;
int a[N];

bool dfs(int now,int ed1,int ed2,int d1,int d2)
{
	if(now==n+1) return 1;
	//第一个序列空
	if(!(~ed1)) return dfs(now+1,a[now],ed2,d1,d2);
	//第二个序列空 能放第一个就放第一个
	if(!(~ed2) && ~d1 && a[now]==ed1+d1) return dfs(now+1,a[now],ed2,d1,d2);
	
	bool ok=0; //第二个序列为空,接在第二个
	if(!(~ed2)) ok|=dfs(now+1,ed1,a[now],d1,d2);
	if(ok) return 1; //第一个序列 1 个数
	if(!(~d1) && ~ed1) ok|=dfs(now+1,a[now],ed2,a[now]-ed1,d2);
	if(ok) return 1; //第二个序列 1 个数
	if(!(~d2) && ~ed2) ok|=dfs(now+1,ed1,a[now],d1,a[now]-ed2);
	if(ok) return 1; //接在第一个
	if(~d1 && ~ed1 && a[now]==ed1+d1) ok|=dfs(now+1,a[now],ed2,d1,d2);
	if(ok) return 1; //接在第二个
	if(~d2 && ~ed2 && a[now]==ed2+d2) ok|=dfs(now+1,ed1,a[now],d1,d2);
	return ok;
}

void solve()
{
	n=fr();
	for(int i=1;i<=n;i++) a[i]=fr();
	puts(dfs(1,-1,-1,-1,-1)?"Yes":"No");
}

int main()
{
	int T=fr();
	while(T--) solve();

	return 0;
}

T2

显然的 \(bfs\) 最短路

一个小优化,对于车和象,每个状态点最多进过一次,一旦从内向外的扩散路径上有点被扩散过,直接 \(break\) 即可

\(O(nm)\)

posted @ 2023-06-08 11:02  xyzfrozen  阅读(13)  评论(0)    收藏  举报