CodeForces - 1327D Infinite Path(图论综合)

Aine ·
更新时间:2024-09-20
· 666 次阅读

题目链接:点击查看

题目大意:首先给出一个 1 ~ n 的排列,用 p 数组表示,再给出给个点的颜色,用 c 数组表示

然后抛出Infinite Path的定义:对于某个 i ,p[ i ] , p[ p[ i ] ] , p[ p[ p[ i ] ] ] 无限嵌套下去,且每个位置的颜色相同,即 c[ i ] = c[ p[ i ] ] = c[ p[ p[ i ] ] ] = c[ p[ p[ p[ i ] ] ] ] 等等等等

下面重载一下排列的乘法运算,假如 a 和 b 是 1 ~ n 的两个排列,那么 a * b = b[ a[ i ] ] ,a * a = a[ a [ i ] ] 

从而重载一下排列的乘方运算,p^k = p * p * p ... * p ( k 个 p )

题目要求我们找到一个最小的 k ,使得给出的排列 p 的 k 次方,存在一个 i ,可以满足上述的Infinite Path

题目分析:读完题后,不难想到如果想要找到Infinite Path的话,必然是一个循环,而 1 ~ n 的一个排列,如果转换为有向图的形式,可以视为数个不相交的有向环,之前做题记住的结论,忘记是怎么证明的了,这样就可以将给出的排列 p 以有向图的形式表示,接下来结合前几周离散数学新学到的知识(学以致用)

 可以将 p^k 这个抽象的概念具体化,简单来说,p^k 就是在 p 这个有向图中,经过长度为 k 的步长可以到达的关系

再换句话说,p^k 就是在环中将距离相隔为 k 的数个点按照原次序重新组合成一个新的环

如果上面这句话不好理解的话,对于题目给出的第三个样例画一下图就好理解了

综上所述,现在题目就转换为了,在数列 p 的所有环中,能否找到一个等差 k ,使得环上所有满足等差关系的位置:pos , pos + k , pos + 2 * k , pos + 3 * k 等等位置的颜色相同,维护这个最小的 k 就是答案了

到此为止这个题目剩下的就是实现了,比赛的时候明明已经到了这一步,却卡在了如何在环上找到等差的位置这里,不会实现,还是自己太菜了啊,赛后看了大佬的代码发现只需要nlogn维护因子就好了,因为如果想满足在环上满足等差,那么这个差值 k 一定是环的长度的因子,对于每个长度的因子,nlogn预处理一下就可以了

代码:
 

#include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; typedef long long LL; typedef unsigned long long ull; const int inf=0x3f3f3f3f; const int N=2e5+100; int p[N],c[N]; bool vis[N]; vectord[N]; int cal(vectorloop) { int mmin=inf; for(auto len:d[loop.size()])//枚举每个因子作为差值 k { for(int i=0;i<len;i++)//枚举起点 { bool flag=true; for(int j=i;j<loop.size();j+=len) { if(c[loop[i]]!=c[loop[j]]) { flag=false; break; } } if(flag) mmin=min(mmin,len); } } return mmin; } int main() { #ifndef ONLINE_JUDGE // freopen("input.txt","r",stdin); // freopen("output.txt","w",stdout); #endif // ios::sync_with_stdio(false); for(int i=1;i<N;i++)//预处理因子 for(int j=i;j>w; while(w--) { int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",p+i); for(int i=1;i<=n;i++) scanf("%d",c+i); for(int i=1;i<=n;i++) vis[i]=false; int ans=n; for(int i=1;i<=n;i++) { if(vis[i]) continue; int k=i; vectorloop;//找环 while(!vis[k]) { loop.push_back(k); vis[k]=true; k=p[k]; } ans=min(ans,cal(loop)); } printf("%d\n",ans); } return 0; }
作者:Frozen_Guardian



path CodeForces 图论 infinite

需要 登录 后方可回复, 如果你还没有账号请 注册新账号