- 有(n)个位置标号为(0sim n-1),初始位置(0)为空,位置(i)上放着编号为(i)的物品。
- 给出空位的最终位置(pos_0),并给定一个序列(c)和一个常数(d)用于生成第(i)个物品的最终位置(pos_i):要求(pos_i=(c_i+d imes x_i+y_i)\%n),(pos_i)不与之前任意(pos_j)重复,且在此前提下首先(y_i)尽可能小,,其次(x_i)尽可能小。
- 每次你可以把一个物品移到空位上,求至少多少次操作能把所有物品移动到对应的最终位置。
- 数据组数(le20),(nle10^5)
最终位置的求解
考虑我们首先要满足(y_i)尽可能小,那么就是要找到最小的(y_i),使得存在一个((d imes x_i+(c_i+y_i))\%n)没有出现过。
令(g=gcd(d,n)),则如果两数(a,b)满足(aequiv b(mod g)),它们((d imes k+r)\%n)的形式中的(r)就相等。
因此,我们考虑开一个(set),存下还有哪些(rin[0,g))仍然存在((d imes k+r)\%n),然后每次就是先尝试找到大于等于(c_i\%g)的最小的可行(r),找不到就找最小的可行(r)。
现在确定了(r)(即确定了(y_i)),我们还要让(x_i)尽可能小。
我们事先预处理出每个数((d imes k+r)\%n)的形式中对应的(k),对于每一个(r)开一个(set)存下还有哪些(k),接下来的查询过程和上面就非常类似了,先尝试找到大于等于当前(k)的最小的可行(k),找不到就找最小的可行(k)。
最少步数
把(pos_i)看作一个置换,把原问题分解为若干个置换环。
如果某个置换环大小为(1),显然无需操作,代价为(0)。
否则,如果只是简单给环转一遍代价为环上元素个数减(1)。但由于我们只能与空位交换,所以对于不包含空位的环,我们需要花费两次代价在最开始把一个元素换出去、在最后把一个元素换回来。
简单讨论一下即可。
代码:(O(Tnlogn))
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
using namespace std;
int n,m,d,pos[N+5],r[N+5],k[N+5],vis[N+5];set<int> S,P[N+5];set<int>::iterator it,jt;
I int gcd(CI x,CI y) {return y?gcd(y,x%y):x;}
namespace FastIO
{
#define FS 100000
#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
char oc,FI[FS],*FA=FI,*FB=FI;
Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
}using namespace FastIO;
int main()
{
RI Tt,i,j,x,c,p,q,g,t;read(Tt);W(Tt--)
{
for(read(n,pos[0],q,p,m,d),g=gcd(n,d),i=0;i^n;++i) vis[i]=0;
for(i=0;i^g;++i) for(S.insert(x=i),j=0;j^(n/g);x=(x+d)%n,++j) P[r[x]=i].insert(k[x]=j);//预处理,把每个数表示成dk+r
P[r[pos[0]]].erase(k[pos[0]]),P[r[pos[0]]].empty()&&(S.erase(r[pos[0]]),0);//删去pos[0]
for(c=0,i=1;i^n;++i) c=(1LL*c*q+p)%m,x=c%n,
(it=S.lower_bound(r[x%d]))==S.end()&&(it=S.begin(),0),//找到最优的r
(jt=P[*it].lower_bound(k[(x+(*it>=x%g?*it-x%g:*it-x%g+g))%n]))==P[*it].end()&&(jt=P[*it].begin(),0),//找到最优的k,注意先把x修改为模n余r的数
pos[i]=(1LL*d*(*jt)+*it)%n,P[*it].erase(jt),P[*it].empty()&&(S.erase(it),0);//记录最终位置,然后删除
for(t=i=0;i^n;++i) if(!vis[x=i]&&pos[i]^i) {c=-1;W(!vis[x]) ++c,vis[x]=1,x=pos[x];t+=c,i&&(t+=2);}printf("%d
",t);//枚举每个置换环简单讨论
}return 0;
}