【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 4
Sample 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
【最后那部分还是很简单的】
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 #define Maxn 1000010 8 #define INF 0xfffffff 9 #define LL long long 10 11 int n,s,m,d; 12 int nt[Maxn],lt[Maxn],fa[Maxn];//环 13 int ntt[Maxn],ltt[Maxn],fax[Maxn];//环集 14 int pos[Maxn],id[Maxn]; 15 LL c[Maxn],q,p; 16 17 int ffa(int x) 18 { 19 if(fa[x]!=x) fa[x]=ffa(fa[x]); 20 return fa[x]; 21 } 22 23 int ffax(int x) 24 { 25 if(fax[x]!=x) fax[x]=ffax(fax[x]); 26 return fax[x]; 27 } 28 29 int gcd(int a,int b) 30 { 31 if(b==0) return a; 32 return gcd(b,a%b); 33 } 34 35 bool vis[Maxn]; 36 37 int main() 38 { 39 int T; 40 scanf("%d",&T); 41 while(T--) 42 { 43 int L; 44 scanf("%d%d%lld%lld%d%d",&n,&s,&q,&p,&m,&d); 45 d%=n; 46 for(int i=0;i<n;i++) nt[i]=(i+d)%n; 47 for(int i=0;i<n;i++) lt[i]=(i-d+n)%n; 48 c[0]=0; 49 for(int i=1;i<n;i++) c[i]=(c[i-1]*q+p)%m; 50 for(int i=0;i<n;i++) fa[i]=i; 51 for(int i=0;i<n;i++) c[i]%=n; 52 if(d!=0) L=gcd(n,d); 53 else L=n; 54 for(int i=0;i<L;i++) fax[i]=i; 55 for(int i=0;i<L;i++) 56 { 57 id[i]=i; 58 int x=nt[i]; 59 while(x!=i) 60 { 61 id[x]=i; 62 x=nt[x]; 63 } 64 } 65 66 memset(vis,1,sizeof(vis)); 67 for(int i=0;i<n;i++) 68 { 69 int nw=ffax(id[c[i]]); 70 71 pos[i]=ffa((c[i]+(nw-id[c[i]]+L)%L)%n); 72 73 if(i==0) pos[i]=s,nw=s%L; 74 if(lt[pos[i]]==pos[i]) 75 { 76 fax[nw]=(nw+1)%L; 77 } 78 else 79 { 80 nt[lt[pos[i]]]=nt[pos[i]]; 81 lt[nt[pos[i]]]=lt[pos[i]]; 82 fa[pos[i]]=nt[pos[i]]; 83 } 84 } 85 LL ans=0; 86 memset(vis,0,sizeof(vis)); 87 for(int i=0;i<n;i++) if(vis[i]==0) 88 { 89 int x=i,cnt=0; 90 bool p=0; 91 while(vis[x]==0) 92 { 93 cnt++; 94 if(x==s) p=1; 95 vis[x]=1; 96 x=pos[x]; 97 } 98 if(cnt>1) 99 { 100 if(p) ans+=cnt-1; 101 else ans+=cnt+1; 102 } 103 } 104 printf("%d\n",ans); 105 } 106 return 0; 107 }
2017-01-13 09:30:25