很作死地写了个高端(SB)的并查集
首先只要求出所有的posi,剩下的很容易用置换群的理论得出答案
然后看posi的求法
对于固定的a,d
a+b*d(modn)
通过b不断地累加会构成环
于是查找的时候只要找环上xi最小的点。
但是有的时候会把一个环用完
于是我们把环上的每个点都连到相应的下一个环上
然后我很脑残地写了个并查集,维护环与环之间的路径和环内的路径
每次查找的时候先通过环间路径找到环,即yi得值
然后通过环内找到xi
最后更新
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=100000+5;
typedef long long ll;
int pa[N],d,n,circle_number[N];
int find1(int x){
return pa[x]==x?x:pa[x]=find1(pa[x]);
}
int find2(int x){
if(d==0||circle_number[x]==circle_number[pa[x]])return x;
return pa[x]=find2(pa[x]);
}
void merge(int x,int y){
x=find1(x);y=find1(y);
if(x!=y)pa[x]=y;
}
bool use[N];
void work(int c){
use[c]=1;
if(find1((c+d)%n)==c){
int r=c;
do{
pa[r]=(r+1)%n;
r=(r+d)%n;
}while(r!=c);
}else merge(c,(c+d)%n);
}
int query(int c){
c=find2(c);
c=find1(c);
int ans=c;
work(c);
return ans;
}
int pos[N];
bool vis[N],flag;
int dfs(int i){
if(vis[i])return 0;
vis[i]=1;if(!i)flag=0;
return dfs(pos[i])+1;
}
void pre(){
memset(vis,0,sizeof(vis));
int tot=0;
for(int i=0;i<n;i++)
if(!vis[i]){
int j=i;
tot++;
do{
vis[j]=1;
circle_number[j]=tot;
j=(j+d)%n;
}while(j!=i);
}
}
int main(){
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
int T;scanf("%d",&T);
while(T--){
ll a,b,m,t;
int s;
scanf("%d%d%lld%lld%lld%lld",&n,&s,&a,&b,&m,&t);
d=t%n;
memset(use,0,sizeof(use));
pre();
for(int i=0;i<n;i++)pa[i]=i;
work(s);
ll c=0;
int ans=0;
for(int i=1;i<n;i++){
c=(c*a+b)%m;
pos[i]=query(c%n);
}
pos[0]=s;
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++)
if(!vis[i]){
flag=1;
int l=dfs(i);
if(l==1)continue;
ans+=l+(flag?1:-1);
}
printf("%d\n",ans);
}
return 0;
}