目录
21.1.30 2016-2017 ACM-ICPC East Central North America Regional Contest (ECNA 2016)
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(模拟) √
因为限制条件很多,所以直接从A
和B
位置开始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;
}