Codeforces Round #545 (Div. 2) EF

E. Museums Tour

题意:有n个城市m条有向边,一周有d天,每个城市的博物馆在d的周期内定时开放和关闭,现在你在起点 1,每隔一天你必须走到相邻的某个城市去,你有无限时间,每个点每条边你也可以走无数次,求最多能欣赏多少个不同的博物馆。

借鉴这位大佬:hwim

思路:我们把每个点拆成d个点,第 i 个点代表第 i 天走到了这个城市,那么对于每条边 u->v,我们枚举天数 i,连接ui->vi+1,代表如果第 i 天走到了 u 点,可以在第 i+1 到达 v点,也就是说,如果我能达到 xi 点,那么时间肯定是第 i 天(mod d),然后根据拆点连接的边建图跑tarjan缩点,对于一个环内点 u,如果在 i 天 u 的博物馆开放,那么就把 ui 所属的的联通快加上一个贡献,且d个 u 只能对同一个联通快产生最多一个贡献,算完贡献,我们从起点所属联通快跑dp,即可求出答案。

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e6+10;
int Laxt[maxn],Next[maxn],To[maxn],cnt;
int Laxt2[maxn],Next2[maxn],To2[maxn],cnt2; 
int d,n,m,dfn[maxn],low[maxn],sk[maxn],vis[maxn];
int sz[maxn],dp[maxn],bel[maxn],Time,scc,top;
char s[100001][51];
void add(int u,int v)
{
	Next[++cnt]=Laxt[u];Laxt[u]=cnt;To[cnt]=v;
}
void add2(int u,int v)
{
	Next2[++cnt2]=Laxt2[u];Laxt2[u]=cnt2;To2[cnt2]=v;
}
int id(int a,int b)
{
	return (a-1)*d+b+1;
}
void tarjan(int u)
{
	dfn[u]=low[u]=++Time;
	sk[++top]=u;vis[u]=1;
	for(int i=Laxt[u];i;i=Next[i])
	{
		int v=To[i];
		if(!dfn[v])
		{
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(vis[v])
		low[u]=min(low[u],dfn[v]);
	}
	if(low[u]==dfn[u])
	{
		++scc;
		do{
			vis[sk[top]]=0;
			bel[sk[top--]]=scc;
		}while(sk[top+1]!=u);
	}
}
int dfs(int u)
{
	if(dp[u])return dp[u];
	int ans=0;
	for(int i=Laxt2[u];i;i=Next2[i])
	ans=max(ans,dfs(To2[i]));
	dp[u]=sz[u]+ans;
	return dp[u];
}
int main()
{
	int u,v;
	scanf("%d%d%d",&n,&m,&d);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&u,&v);
		for(int j=0;j<d;j++)
		add(id(u,j),id(v,(j+1)%d));
	}
	for(int i=1;i<=n;i++)
	scanf("%s",s[i]);
	for(int i=1;i<=n*d;i++)
	if(!dfn[i])tarjan(i);
	for(int i=1;i<=n;i++)
	for(int j=0;j<d;j++)
	{
		int x=id(i,j);
		if(s[i][j]=='1'&&vis[bel[x]]!=i)
		vis[bel[x]]=i,sz[bel[x]]++;
		for(int k=Laxt[x];k;k=Next[k])
		{
			int v=To[k];
			if(bel[x]!=bel[v])
			add2(bel[x],bel[v]);
		}
	}
	printf("%d\n",dfs(bel[1]));
}

F. Cooperative Game

题意:有10个人在链的起点,链的终点连接一个有向环,每次可以往前移动若干人一个距离,然后系统会告诉你这些人所在不同地点的个数,要你把10个人全部移到链和环的交点上去,链和环长度未知。

思路:先把 1 往前移动 s 次,2 往前移动 2s次 直到他们两相遇,假设环长度m,相遇地点距交点x,环长度为n,那么s=m+x+i*n,2s=m+x+j*n,相减得 s=(j-i)*n,那么m=(j-2*i)n-x,这个时候我们知道起点到交点的距离等于若干环的周长-x,那么此时我同时移动所有人,当他们第一次相遇时,肯定是在交点,搞定。

#include<bits/stdc++.h>
using namespace std;
int res;
int getv()
{
    int x;
    cin>>res;
    for(int i=1;i<=res;i++)
        scanf("%d",&x);
}
int main()
{
    do
    {
        puts("next 0");getv();
        puts("next 0 1");getv();
    }while(res==3);
    do
    {
        puts("next 0 1 2 3 4 5 6 7 8 9");
        getv();
    }while(res==2);
    puts("done");
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长沙橘子猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值