题解:P3207 [HNOI2010] 物品调度
P3207 [HNOI2010] 物品调度
题意
题面有点令人犯恶心,先理清楚:
首先有个需要你生成的数组
生成规则是:
每个盒子还有一个最终位置为
每次移动可以将某一个盒子移到空位上,问把所有的盒子移动到最终位置所需的最少步数。
解法
其实比较容易可以发现,增加
求答案的时候就需要判断一下这个置换环内有没有空格,如果有空格就是环内元素个数减
注意的点
有一些小细节可以根据代码理解。
code
#include<bits/stdc++.h>
#define int long long
#define N 100005
using namespace std;
bool vis[N];
int T,n,s,p,q,m,d,ans,a[N],c[N],fa[N],pos[N];
int find(int x){return fa[x]==x?x:(fa[x]=find(fa[x]));}
signed main(){
scanf("%lld",&T);
while(T--){
scanf("%lld%lld%lld%lld%lld%lld",&n,&s,&p,&q,&m,&d);
for(int i=0;i<n;i++) a[i]=0,fa[i]=i,vis[i]=0;
vis[pos[0]=s]=1,ans=c[0]=0,fa[s]=(s+d)%n;
for(int i=1;i<n;i++) c[i]=(c[i-1]*p+q)%m;
for(int i=1;i<n;i++){
int y=0;
while(vis[find((y+c[i])%n)]) y++;
pos[i]=find((y+c[i])%n);
vis[pos[i]]=1,fa[pos[i]]=find((pos[i]+d)%n);
}
for(int i=0;i<n;i++) if(!a[i]&&pos[i]!=i){
bool pd=0;
int p=i,cnt=0;
while(!a[p]){
if(!p) pd=1;
a[p]=1,p=pos[p],cnt++;
}
ans+=cnt+(pd?-1:1);
}
printf("%lld\n",ans);
}
return 0;
}