Codeforces Round #605 (Div. 3) 補題(E最短路/多源bfs、Fdp+輸出路徑)

E. Nearest Opposite Parity(最短路)

n(n<=2e5)個數的數組a[],第i個數可以跳到i-a[i]或i+a[i],

若a[i]跳到一個與其奇偶性不同的a[j]即可認爲對於i來說跳躍終止。

對於每個i,求最短的跳躍終止的距離。

 

建反圖,i-a[i]連向i代價1,i+a[i]連向i代價1,所有偶點連超級偶點代價0,所有奇點連超級奇點代價0

這樣本來所有奇點到超級偶點的最短路,可認爲是超級偶點到所有奇點的最短路

同理,跑一次超級奇點到所有偶點的最短路,粘一下dij板子就過了

dfs由於有環的更新順序故不可行,也可以不實際建出超級源點,

考慮多源bfs,補一下多源bfs的做法,感覺很簡潔

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,a[N],dis[N],ans[N];
vector<int>e[N];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
	{
		scanf("%d",&a[i]);
		if(i-a[i]>=1)e[i-a[i]].push_back(i);
		if(i+a[i]<=n)e[i+a[i]].push_back(i);
	}
	for(int d=0;d<2;++d)
	{
		memset(dis,-1,sizeof dis);
		queue<int>q;
		for(int i=1;i<=n;++i)
		{
			if((a[i]&1)==d)
			{
				dis[i]=0;
				q.push(i);
			}
		}
		while(!q.empty())
		{
			int u=q.front();
			q.pop();
			for(int v:e[u])
			{
				if(dis[v]==-1)
				{
					dis[v]=dis[u]+1;
					q.push(v);
				}
			}
		}
		for(int i=1;i<=n;++i)
		{
			if((a[i]&1)!=d)
			{
				ans[i]=dis[i];
			}
		}
	}
	for(int i=1;i<=n;++i)
	printf("%d%c",ans[i]," \n"[i==n]);
	return 0;
} 

F. Two Bracket Sequences(bfs+dp)

給你兩個不超過200的不一定合法的括號序列

輸出一個最短的合法的括號串,使得這兩個括號序列都是這個串的子序列

 

子序列匹配顯然越前出現越好,所以dp2選1去枚舉當前選左括號還是選右括號,貪心地和當前位置對應匹配

dp[i][j][k]代表當前該匹配s的第i個字母 該匹配t的第j個字母 且有k個左括號未匹配(左括號比右括號多k個)

狀態數降到200*200*400,pre[i][j][k]直接暴力記錄前驅是哪個三元組即可,空間足夠

最後答案即爲dp[n][m][0]的值,然後根據前驅倒序輸出路徑

#include<bits/stdc++.h>
using namespace std;
const int N=205,M=405;
int n,m,d[N][N][M],cnt;
char s[N],t[N],res[M];
struct pos
{
	int x,y,z;
}pre[N][N][M],now,las;
void solve()
{
	int x,y,z,xx,yy,zz;
	memset(d,-1,sizeof d);
	queue<pos>q;
	q.push({0,0,0});
	d[0][0][0]=0;
	while(!q.empty())
	{
		now=q.front();
		q.pop();
		x=now.x,y=now.y,z=now.z;
		for(char c:{'(',')'})
		{
			xx=x,yy=y,zz=z;
			if(xx<n&&s[xx]==c)xx++;
			if(yy<m&&t[yy]==c)yy++;
			if(c=='(')zz++;
			else zz--;
			if(zz<0||zz>=M)continue;
			if(d[xx][yy][zz]==-1)
			{
				d[xx][yy][zz]=d[x][y][z]+1;
				pre[xx][yy][zz]={x,y,z};
				if(xx==n&&yy==m&&zz==0)
				{
					las={xx,yy,zz};
					return;
				}
				q.push({xx,yy,zz});
			}
		}
	}
}
int main()
{
	scanf("%s%s",s,t);
	n=strlen(s);m=strlen(t);
	solve();
	int x,y,z;
	while(1)
	{
		now=las;
		x=now.x,y=now.y,z=now.z;
		if(x+y+z==0)break;
		if(pre[x][y][z].z<z)res[cnt++]='(';
		else res[cnt++]=')';
		las=pre[x][y][z];
	}
	reverse(res,res+cnt);
	res[cnt++]='\0';
	printf("%s\n",res);
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章