题目
思路来源
rui_er代码
题解
不难发现,i->pi形成一个置换环,每个置换环有一个长度,
需要确定一个旋转次数x,使得x%cyc[1]=mn[1],x%cyc[2]=mn[2],等等
其中cyc[1]是从前到后遇到的第一个环的环长,
mn[1]为了将第一个环这个环的最小值旋转到首位时的旋转次数
然后再遇到第二个环的时候,需要在满足第一个取模条件成立的约束条件下,
找到符合约束条件的位置的最小值mn[2],再令x%cyc[2]=mn[2],并旋转
重复这个操作直到最后一个环
注意到环长最大1e5,几个数乘起来爆了long long,所以暴力excrt解是否存在合法x显然不可行
因为cyc[1]+cyc[2]+...=n,总环长是n,所以当前环长是可枚举的
一个直观地观察是,
如果前面已经遇到了一个x%6=1,那么再遇到长为6的环的时候,显然只能选x%6=1
事实上,约束是按质因子限制的
可以枚举cyc[i]的每个质因子p,把当前mn[i]%p的值记录下来,记为remain[p]
后面的环长cyc[i+1]对应枚举mn[i+1]的时候,如果再遇到remain[p]的话,不能冲突,
冲突的话,说明这个旋转次数,对应把位置旋到第一位当最小值时,不合法
遍历环长个位置,找到每个环的合法位置中最小的,然后进行旋转操作即可
根据学弟的问题补充一下说明
1. x%6=1的时候,令x=1+6k,一定有x%2=1,x%3=1
2. 根据CRT,x%2=1,x%3=1能反推出x%6=1,
所以一个约束只需转化成对其所有质因子的约束,质因子的约束能联合其中任意个,还原出对应乘积的原约束
3. 如果说前面我得到了一组不同质因数remain的解,但是到某一个环,发现无论如何都没有解,这种情况是否会发生
前面得到了一组不同质因数remain的解,这意味着至少能反解出来一个x,用这个x去模这个环长得到的数,就是这个环的解
代码
#include <bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<vector>
#include<map>
#include<set>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair<int,int> P;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<<x<<" ";
#define dbg2(x) cerr<<(#x)<<":"<<x<<endl;
#define SZ(a) (int)(a.size())
#define sci(a) scanf("%d",&(a))
#define pt(a) printf("%d",a);
#define pte(a) printf("%d\n",a)
#define ptlle(a) printf("%lld\n",a)
#define debug(...) fprintf(stderr, __VA_ARGS__)
using namespace std;
const int N=2e5+10;
vector<int>fac[N];
int n,p[N],a[N],ans[N],rem[N];
bool vis[N];
int gcd(int x,int y){return !y?x:gcd(y,x%y);}
void sol(){
memset(rem,-1,sizeof rem);
for(int i=1;i<N;i++){
for(int j=i;j<N;j+=i){
fac[j].pb(i);
}
}
sci(n);
rep(i,1,n)sci(p[i]);
rep(i,1,n)sci(a[i]);
rep(i,1,n){
if(p[i]==i){ans[i]=a[i];continue;}
if(vis[i])continue;
int mn=n+1,nc,c=0;
vector<int>tmp;
for(int j=i;!vis[j];j=p[j],c++){
tmp.pb(j);
vis[j]=1;
}
//printf("mn:%d nc:%d\n",mn,nc);
int sz=SZ(tmp);//x%sz=nc
rep(j,0,sz-1){
bool ok=1;
for(auto &d:fac[sz]){
if(rem[d]==-1)continue;
if((j%d)!=rem[d]){
ok=0;
break;
}
}
if(!ok)continue;
if(mn>a[tmp[j]])mn=a[tmp[j]],nc=j;
}
rep(j,0,sz-1){
ans[tmp[j]]=a[tmp[(j+nc)%sz]];
}
for(auto &d:fac[sz]){
rem[d]=nc%d;
}
}
rep(i,1,n){
printf("%d%c",ans[i]," \n"[i==n]);
}
}
int main(){
sol();
return 0;
}
/*
1->3
2->1
3->5
5->2
4 3 1 6
1 4 2 5
ai=api
1 2 3 4
1 2 3 4 5 6
gcd(4,6)=2
*/