题意:给出一个数组 c[i] ,求一个数组 pos[i]=d∗xi+yi+c[i] 满足对于任意 j<i , pos[i]!=pos[j] 。并且满足最小化 yi 的前提下最小化 xi 后面的不说了。
从前到后枚举,如果当前点没有被访问过,从当前点
i
开始枚举
当
yi+1
时会从当前环转移到其他环,因此如果
c[i]
所对应的环上的点还有剩余那么从当前环上取一个点,否则增加
yi
,从其他环上选点。
可以用类似并查集的东西维护一下。
#include <bits/stdc++.h>
using namespace std;
#define N 110000
#define ll long long
int T,n,s,q,p,m,d;
int c[N],use[N],vis[N],pos[N],cnt[N],bel[N];
int fa[N],done[N];
int find(int x)
{
if(cnt[bel[x]])return x==fa[x] ? fa[x]:fa[x]=find(fa[x]);
if(!done[x])done[x]=1,fa[x]=(x+1)%n;
if(!cnt[bel[fa[x]]])
{
int ret=find(fa[x]);
fa[x]=fa[fa[x]];
return ret;
}
return find(fa[x]);
}
int main()
{
scanf("%d",&T);
while(T--)
{
int ans=0;
memset(use,0,sizeof(use));
memset(vis,0,sizeof(vis));
memset(done,0,sizeof(done));
scanf("%d%d%d%d%d%d",&n,&s,&q,&p,&m,&d);
c[0]=0;d%=n;pos[0]=s;
if(!d)d++;
for(int i=1;i<n;i++)c[i]=((ll)c[i-1]*q+p)%m;
for(int i=0;i<n;i++)fa[i]=i;
for(int i=0;i<n;i++)
if(!use[i])
{
cnt[i]=0;
for(int j=i;!use[j];j=(j+d)%n)
use[j]=1,bel[j]=i,cnt[i]++;
}
fa[s]=(s+d)%n;cnt[bel[s]]--;
for(int i=1,t;i<n;i++)
{
pos[i]=find(c[i]%n);
if(--cnt[bel[pos[i]]])
fa[pos[i]]=find((pos[i]+d)%n);
}
for(int i=0;i<n;i++)
if(!vis[i])
{
vis[i]=1;int cnt=1,flag=0;
if(!i)flag=2;
for(int j=pos[i];!vis[j];j=pos[j])
{
vis[j]=1;cnt++;
if(!j)flag=2;
}
if(cnt==1)continue;
ans+=cnt+1-flag;
}
printf("%d\n",ans);
}
return 0;
}