专栏文章
题解:P3207 [HNOI2010] 物品调度
P3207题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mimzt2ya
- 此快照首次捕获于
- 2025/12/01 18:14 3 个月前
- 此快照最后确认于
- 2025/12/01 18:14 3 个月前
P3207 [HNOI2010] 物品调度
题意
题面有点令人犯恶心,先理清楚:
首先有个需要你生成的数组 ,生成所需变量是用题目给你的:、 和 。
生成规则是:, 。
每个盒子还有一个最终位置为, 。注意,这个 和 你是不知道的,要你自己生成。满足首先 的字典序要最小,其次是 的字典序也要小。
每次移动可以将某一个盒子移到空位上,问把所有的盒子移动到最终位置所需的最少步数。
解法
其实比较容易可以发现,增加 会使得整个序列在操作的时候变成一个环,环与环之间的关系又要由 来决定。此时就可以使用并查集进行优化,把使用了的位置连向空位。
求答案的时候就需要判断一下这个置换环内有没有空格,如果有空格就是环内元素个数减 ,否则加 。什么意思呢?如下图:

注意的点
有一些小细节可以根据代码理解。
code
CPP#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;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...