【BZOJ 1998】 1998: [Hnoi2010]Fsk物品调度(双向链表+并查集+置换)
1998: [Hnoi2010]Fsk物品调度
Description
现在找工作不容易,Lostmonkey费了好大劲才得到fsk公司基层流水线操作员的职位。流水线上有n个位置,从0到n-1依次编号,一开始0号位置空,其它的位置i上有编号为i的盒子。Lostmonkey要按照以下规则重新排列这些盒子。 规则由5个数描述,q,p,m,d,s,s表示空位的最终位置。首先生成一个序列c,c0=0,ci+1=(ci*q+p) mod m。接下来从第一个盒子开始依次生成每个盒子的最终位置posi,posi=(ci+d*xi+yi) mod n,xi,yi是为了让第i个盒子不与之前的盒子位置相同的由你设定的非负整数,且posi还不能为s。如果有多个xi,yi满足要求,你需要选择yi最小的,当yi相同时选择xi最小的。 这样你得到了所有盒子的最终位置,现在你每次可以把某个盒子移动到空位上,移动后原盒子所在的位置成为空位。请问把所有的盒子移动到目的位置所需的最少步数。Input
第一行包含一个整数t,表示数据组数。接下来t行,每行6个数,n,s,q,p,m,d意义如上所述。 对于30%的数据n<=100,对于100%的数据t<=20,n<=100000,s<n。其余所有数字均为不超过100000的正整数。 <="" div="">Output
对于每组数据输出一个数占一行,表示最少移动步数。Sample Input
1
8 3 5 2 7 4Sample Output
6HINT
说明:第1个到第7个盒子的最终位置依次是:2 5 6 4 1 0 7
计算过程可能超过整型范围。Source
【分析】
啊,我好笨。
先看那两个公式。
ci+1=(ci*q+p) mod m
posi=(ci+d*xi+yi) mod n
观察题目就知道主要是求pos数组,后面的就是置换的很基本的东西,弄成循环就好了。
pos数组怎么求呢,当然暴力是会超时的。
观察一下他的形式,发现如果yi也固定,那么走的是一个环。
如果这个环里面所有元素都被取走了,那么就跳到下一个环,直到环里面有东西为止。
就是模拟一个这样的过程,然后当然虽说是跳直到找到有环,但当然还是不能这样做的,所以我用了并查集和双向链表搞这个东西。
环的数量是gcd(n,d)【表示我一开始还搞错这个很久
求出pos数组之后,把置换分成互不相交的循环
若循环长度>1,且空格在里面,则ans+=L-1
否则ans+=L+1
【最后那部分还是很简单的】
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define Maxn 1000010
#define INF 0xfffffff
#define LL long long int n,s,m,d;
int nt[Maxn],lt[Maxn],fa[Maxn];//环
int ntt[Maxn],ltt[Maxn],fax[Maxn];//环集
int pos[Maxn],id[Maxn];
LL c[Maxn],q,p; int ffa(int x)
{
if(fa[x]!=x) fa[x]=ffa(fa[x]);
return fa[x];
} int ffax(int x)
{
if(fax[x]!=x) fax[x]=ffax(fax[x]);
return fax[x];
} int gcd(int a,int b)
{
if(b==) return a;
return gcd(b,a%b);
} bool vis[Maxn]; int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int L;
scanf("%d%d%lld%lld%d%d",&n,&s,&q,&p,&m,&d);
d%=n;
for(int i=;i<n;i++) nt[i]=(i+d)%n;
for(int i=;i<n;i++) lt[i]=(i-d+n)%n;
c[]=;
for(int i=;i<n;i++) c[i]=(c[i-]*q+p)%m;
for(int i=;i<n;i++) fa[i]=i;
for(int i=;i<n;i++) c[i]%=n;
if(d!=) L=gcd(n,d);
else L=n;
for(int i=;i<L;i++) fax[i]=i;
for(int i=;i<L;i++)
{
id[i]=i;
int x=nt[i];
while(x!=i)
{
id[x]=i;
x=nt[x];
}
} memset(vis,,sizeof(vis));
for(int i=;i<n;i++)
{
int nw=ffax(id[c[i]]); pos[i]=ffa((c[i]+(nw-id[c[i]]+L)%L)%n); if(i==) pos[i]=s,nw=s%L;
if(lt[pos[i]]==pos[i])
{
fax[nw]=(nw+)%L;
}
else
{
nt[lt[pos[i]]]=nt[pos[i]];
lt[nt[pos[i]]]=lt[pos[i]];
fa[pos[i]]=nt[pos[i]];
}
}
LL ans=;
memset(vis,,sizeof(vis));
for(int i=;i<n;i++) if(vis[i]==)
{
int x=i,cnt=;
bool p=;
while(vis[x]==)
{
cnt++;
if(x==s) p=;
vis[x]=;
x=pos[x];
}
if(cnt>)
{
if(p) ans+=cnt-;
else ans+=cnt+;
}
}
printf("%d\n",ans);
}
return ;
}
2017-01-13 09:30:25
【BZOJ 1998】 1998: [Hnoi2010]Fsk物品调度(双向链表+并查集+置换)的更多相关文章
- BZOJ_1998_[Hnoi2010]Fsk物品调度_并查集+置换
BZOJ_1998_[Hnoi2010]Fsk物品调度_并查集+置换 Description 现在找工作不容易,Lostmonkey费了好大劲才得到fsk公司基层流水线操作员的职位.流水线上有n个位置 ...
- 【BZOJ 1998】[Hnoi2010]Fsk物品调度 置换群+并查集
置换群的部分水得一比,据说是经典的置换群理论(然而我并不知道这理论是啥).重点就在于怎么求pos!!!容易发现这个东西是这样的:每次寻找pos,先在本环里找,找不到再往下一个环里找,直到找到为止……一 ...
- BZOJ 1998: [Hnoi2010]Fsk物品调度 [置换群 并查集]
传送门 流水线上有n个位置,从0到n-1依次编号,一开始0号位置空,其它的位置i上有编号为i的盒子.Lostmonkey要按照以下规则重新排列这些盒子. 规则由5个数描述,q,p,m,d,s,s表示空 ...
- [BZOJ1998][Hnoi2010]Fsk物品调度
[BZOJ1998][Hnoi2010]Fsk物品调度 试题描述 现在找工作不容易,Lostmonkey费了好大劲才得到fsk公司基层流水线操作员的职位.流水线上有n个位置,从0到n-1依次编号,一开 ...
- 【BZOJ1998】[HNOI2010]物品调度(并查集,模拟)
[BZOJ1998][HNOI2010]物品调度(并查集,模拟) 题面 BZOJ,为啥这题都是权限题啊? 洛谷 题解 先不管\(0\)位置是个空,把它也看成一个箱子.那么最终的答案显然和置换循环节的个 ...
- 【BZOJ】1998: [Hnoi2010]Fsk物品调度
http://www.lydsy.com/JudgeOnline/problem.php?id=1998 题意: 给你6个整数$n,s,q,p,m,d$. 有$n$个位置和$n-1$个盒子,位置编号从 ...
- HNOI 2010 物品调度 并查集 置换
题意: 题意有点细,暂不概括.请仔细审题. 分析: 我们先要把c生成出来. 记得颜神讲这道题,首先表明,这道题有两个问题需要处理. 第一个是要先定位,第二个是要求最小移动步数. 定位时对于每一个物品i ...
- 【BZOJ】1202: [HNOI2005]狡猾的商人(并查集+前缀和)
http://www.lydsy.com/JudgeOnline/problem.php?id=1202 用并查集+前缀和. 前缀和从后向前维护和,并查集从前往后合并 对于询问l, r 如果l-1和r ...
- 【BZOJ】1016: [JSOI2008]最小生成树计数 深搜+并查集
最小生成树计数 Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小 ...
随机推荐
- Tomcat 7下如何利用 catalina.properties 部署公用类
Tomcat 有很多配置文件,其中一个是 catalina.properties ,本文介绍catalina.properties 中的设置项. 一.组成 catalina.properties ...
- 关于SQL注入的五大报错注入函数
~全部都以查user()为例子~ 1.floor()id = 1 and (select 1 from (select count(*),concat(version(),floor(rand(0) ...
- 关于RecylerView:1.在ScrollView的RecylerView滑动事件的处理。2.item之间的距离 小数取整
1.在ScrollView的RecylerView滑动事件的处理. 在布局文件中在RecylerView外包裹一层相对布局 2.RecylerView item之间的距离 (1)编写SpaceItem ...
- 将资源文件夹中的文件通过流的方式写入到应用的File文件夹中
//1.在Files文件夹中创建同名的数据库文件 File files = getFilesDir(); File file = new File(files, DBName); if(file.ex ...
- 使用yo -v查看yeoman版本号
使用yo -v无法查看yeoman版本,这是旧版本的方法 新版本使用yo --version即可查看
- [Leetcode Week15] Add Two Numbers
Add Two Numbers 题解 原创文章,拒绝转载 题目来源:https://leetcode.com/problems/add-two-numbers/description/ Descrip ...
- ktime使用例子【原创】
#include <linux/kernel.h>#include <linux/init.h>#include <linux/module.h>#include ...
- H5对安卓WeView开发中的影响
1.body,或者html 高度为100% 会导致下拉直接触发原生的刷新控件,而不是webView滑动到顶部后刷新,以及不会执行onScrollChanged 方法,并且getScrollY 总是返 ...
- f1 f12热键关闭
fn+f2进入bios系统——>找到configuration——>Hotkey Mode——>enter——>选择disable——>fn+f10保存
- google fcm 推送的流程
总结:1.给一个人推,能成功,2.给多个人推,有两种,一种是给组推,一种是给主题推,之前用的是组推,但是不成功,这里换成主题推: <?phpnamespace App\Http\Controll ...