很作死地写了个高端(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; }