• 【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

    6

    HINT

    说明:第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
    ",ans);
    105     }
    106     return 0;
    107 }
    View Code

    2017-01-13 09:30:25

  • 相关阅读:
    C语言|博客作业07
    C语言|博客作业06
    C语言|博客作业05
    C语言|博客作业04
    C语言|博客作业03
    C语言I博客作业02
    我的第一周作业!
    第三周作业
    读书笔记《莫让青春沾染暮气》
    第二周作业
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/6281512.html
Copyright © 2020-2023  润新知