2016-2017 ACM-ICPC East Central North America Regional Contest (ECNA 2016) (B, D, G, H)


21.1.30 2016-2017 ACM-ICPC East Central North America Regional Contest (ECNA 2016)

CF GYM 101196

F 裸区间DP,gcd预处理下。I 网络流签到题。
迷惑的一场,8题两个多小时做完就只能划水了。


B. Foosball Dynasty √

/*
简单模拟 拿个queue 
*/
#include <bits/stdc++.h>
#define pc putchar
#define gc() getchar()
using namespace std;
typedef long long LL;
const int N=1e3+5;

char s[N];
string name[N];

inline int read()
{
	int now=0,f=1; char c=gc();
	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
	for(;isdigit(c);now=now*10+c-48,c=gc());
	return now*f;
}

int main()
{
	int n=read();
	for(int i=1; i<=n; ++i) std::cin>>name[i];
	scanf("%s",s+1); int m=strlen(s+1);

	static std::queue<int> q;
	for(int i=5; i<=n; ++i) q.push(i);
	int now=0,wo=1,bo=2,wd=3,bd=4,mx=0,las=-1;//las=0:W las=1:B
	for(int i=1; i<=m; ++i)
		if(s[i]=='B')
		{
			if(las==1) ++now;
			else now=1;
			las=1, mx=std::max(mx,now);
			std::swap(bo,bd);
			q.push(wd), wd=wo, wo=q.front(), q.pop();
		}
		else
		{
			if(las==0) ++now;
			else now=1;
			las=0, mx=std::max(mx,now);
			std::swap(wo,wd);
			q.push(bd), bd=bo, bo=q.front(), q.pop();
		}

	int ans=mx; while(!q.empty()) q.pop();
	for(int i=5; i<=n; ++i) q.push(i);
	now=0,wo=1,bo=2,wd=3,bd=4,mx=0,las=-1;//las=0:W las=1:B
	for(int i=1; i<=m; ++i)
		if(s[i]=='B')
		{
			if(las==1) ++now;
			else now=1;
			las=1;
			std::swap(bo,bd);
			if(now==ans)
			{
				int a=now&1?bo:bd,b=now&1?bd:bo;
				if(now==i) std::swap(a,b);
				std::cout<<name[a]<<' '<<name[b]<<'
';
			}
			q.push(wd), wd=wo, wo=q.front(), q.pop();
		}
		else
		{
			if(las==0) ++now;
			else now=1;
			las=0;
			std::swap(wo,wd);
			if(now==ans)
			{
				int a=now&1?wo:wd,b=now&1?wd:wo;
				if(now==i) std::swap(a,b);
				std::cout<<name[a]<<' '<<name[b]<<'
';
			}
			q.push(bd), bd=bo, bo=q.front(), q.pop();
		}
	

	return 0;
}

D. Lost in Translation(BFS) √

深度要最小:用BFS!深度最小时可以更新dis。
怎么就容易忘了最简单的那种BFS分层呢。(注意一下状态数)

//31ms	4000KB
#include <bits/stdc++.h>
#define pc putchar
#define gc() getchar()
using namespace std;
typedef long long LL;
const int N=1e5+5;

bool vis[N];
int dep[N];
LL dis[N];
struct Node2
{
	int x,dep;
	LL val;
};

struct Node{
	int to,val;
};
vector<Node> e[N];
map<string,int> mp;

inline int read()
{
	int now=0,f=1; char c=gc();
	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
	for(;isdigit(c);now=now*10+c-48,c=gc());
	return now*f;
}

int main()
{
	int n=read()+1,m=read();
	string s="English",t; mp[s]=1;
	for(int i=2; i<=n; ++i) cin>>s, mp[s]=i;
	int tot=n;
	for(int i=1,u,v,w; i<=m; ++i)
	{
		cin>>s, cin>>t;
		u=mp[s], v=mp[t], w=read();
		e[u].push_back((Node){v,w}), e[v].push_back((Node){u,w});
	}

	static std::queue<Node2> q;
	LL ans=0; q.push((Node2){1,0,0});
	memset(dis,0x3f,sizeof dis);
	for(int i=1; i<=n; ++i) dep[i]=N;
	while(!q.empty())
	{
		Node2 p=q.front(); q.pop();
		int x=p.x;
		dep[x]=std::min(dep[x],p.dep);
		if(p.dep==dep[x]) dis[x]=std::min(dis[x],p.val);
		if(vis[x]) continue;
		vis[x]=1;
		for(auto v:e[x])
			q.push((Node2){v.to,p.dep+1,v.val});
	}
	for(int i=1; i<=n; ++i)
		if(!vis[i]) return puts("Impossible"),0;
		else ans+=dis[i];
	printf("%lld
",ans);
	

	return 0;
}

G. That's One Hanoi-ed Teacher(汉诺塔递归)

需要复习一下汉诺塔。汉诺塔的递归是这样的:

void DFS(int n,int a,int b,int c)//第n个圆盘从a->c
{
	if(n==1)
	{
		printf("%d: %d->%d
",n,a,c);
		return;
	}
	DFS(n-1,a,c,b);
	printf("%d: %d->%d
",n,a,c);
	DFS(n-1,b,a,c);
}

总过程是,将圆盘(n-1)(a)移到(b),将圆盘(n)(a)移到(c),最后将圆盘(n-1)(b)移到(c)
所以这个题,从(n)开始判断:

  • 如果(n)仍在(a)上,则还至少需(1)步将(n)移到(c),和(2^{n-1}-1)步将(n-1)个盘子从(b)移到(c),然后再看(n-1)是否已经从(a)移到(b)上;
  • 如果(n)(b)上,则不是最优解;
  • 如果(n)(c)上,则(n-1)已到过(b),再看(n-1)是否已从(b)移到(c)即可。

类似地递归一下,注意修改当前的参数(a,b,c)就可以了。

//30ms	0KB
#include <bits/stdc++.h>
#define pc putchar
#define gc() getchar()
typedef long long LL;
const int N=105;

int vis[N];
LL ans;

inline int read()
{
	int now=0,f=1; char c=gc();
	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
	for(;isdigit(c);now=now*10+c-48,c=gc());
	return now*f;
}
bool DFS(int n,int a,int b,int c)
{
	if(!n) return 1;
	if(vis[n]==a) return ans+=1ll<<(n-1),DFS(n-1,a,c,b);//n还在a,判断n-1是否已从a移到b去 
	else if(vis[n]==c) return DFS(n-1,b,a,c);//n已经到c,判断n-1是否已从b移回到c去 
	return 0;
}

int main()
{
	int a=read(); for(int i=1; i<=a; ++i) vis[read()]=1;
	int b=read(); for(int i=1; i<=b; ++i) vis[read()]=2;
	int c=read(); for(int i=1; i<=c; ++i) vis[read()]=3;
	if(!DFS(a+b+c,1,2,3)) puts("No");
	else printf("%lld
",ans);

	return 0;
}

H. Vin Diagrams(模拟) √

因为限制条件很多,所以直接从AB位置开始DFS,求出每个X属于的方阵,然后再对方阵里面的点DFS。至于交,可以先分别DFS整个A方阵和B方阵中的点,被DFS两次的点即交。
然后想找到A或B方阵中的某个点,可以找到方阵的左上角((i,j)),那么((i+1,j+1))一定在该方阵中,从它开始DFS即可。

//30ms	400KB
#include <bits/stdc++.h>
#define pc putchar
#define gc() getchar()
#define OK(x,y) (x>=1 && x<=n && y>=1 && y<=m)
typedef long long LL;
const int N=105,Way[5]={1,0,-1,0,1};//down,left,up,right

int n,m,Ans[5],bel[N][N];//1:A 2:B 3:intersection
char s[N][N];
int vis[N][N],vis2[N][N];

inline int read()
{
	int now=0,f=1; char c=gc();
	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
	for(;isdigit(c);now=now*10+c-48,c=gc());
	return now*f;
}
void DFS(int x,int y,int val,int pre)
{
	int t=0;
	for(int i=0; i<4; ++i)
	{
		int xn=x+Way[i],yn=y+Way[i+1];
		if(OK(xn,yn)) t+=s[xn][yn]!='.';
	}
	if(t==4)
	{
		bel[x][y]=3;
		for(int i=0; i<4; ++i)
			if(i==pre)
			{
				int xn=x+Way[i],yn=y+Way[i+1];
				if(OK(xn,yn)&&s[xn][yn]=='X'&&!bel[xn][yn]) DFS(xn,yn,val,i);
			}
	}
	else
	{
		bel[x][y]=val, assert(t==2);
		for(int i=0; i<4; ++i)
		{
			int xn=x+Way[i],yn=y+Way[i+1];
			if(OK(xn,yn)&&s[xn][yn]!='.'&&(!bel[xn][yn]||bel[xn][yn]==3)) DFS(xn,yn,val,i);
		}
	}
}
void DFS2(int x,int y,int val)
{
	vis[x][y]+=val, vis2[x][y]=1;
	for(int i=0; i<4; ++i)
	{
		int xn=x+Way[i],yn=y+Way[i+1];
		if(OK(xn,yn)&&bel[xn][yn]!=val&&bel[xn][yn]!=3&&!vis2[xn][yn]) DFS2(xn,yn,val);
	}
}
void Calc(int val)
{
	memset(vis2,0,sizeof vis2);
	for(int i=1; i<=n; ++i)
		for(int j=1; j<=m; ++j)//找一个最左上角的,它的右下一定在封闭图形里面 
			if(bel[i][j]==val) {DFS2(i+1,j+1,val); return;}
}

int main()
{
	int n=read(),m=read(); ::n=n, ::m=m;
	for(int i=1; i<=n; ++i) scanf("%s",s[i]+1);
	for(int i=1; i<=n; ++i)
		for(int j=1; j<=m; ++j)
			if(s[i][j]=='A'||s[i][j]=='B') DFS(i,j,s[i][j]=='A'?1:2,0);
	Calc(1), Calc(2);

	for(int i=1; i<=n; ++i)
		for(int j=1; j<=m; ++j) if(!bel[i][j]) ++Ans[vis[i][j]];
	printf("%d %d %d
",Ans[1],Ans[2],Ans[3]);
	

	return 0;
}

------------------------------------------------------------------------------------------------------------------------
无心插柳柳成荫才是美丽
有哪种美好会来自于刻意
这一生波澜壮阔或是不惊都没问题
只愿你能够拥抱那种美丽
------------------------------------------------------------------------------------------------------------------------
原文地址:https://www.cnblogs.com/SovietPower/p/14351407.html