【BZOJ1998】[HNOI2010]物品調度(並查集,模擬)
阿新 • • 發佈:2018-10-25
turn show else int 維護 sin size problem pro 值,檢查\(y\)固定時,對應的這個環上是否還有空位,如果有就放進去。這個空位可以用並查集維護,每次將當前放完的位置指向下一個位置,即\(+d\)的位置。
【BZOJ1998】[HNOI2010]物品調度(並查集,模擬)
題面
BZOJ,為啥這題都是權限題啊?
洛谷
題解
先不管\(0\)位置是個空,把它也看成一個箱子。那麽最終的答案顯然和置換循環節的個數相關,對於大小為\(1\)的循環,顯然就是不要動。對於大小為\(L\)的循環,如果包含\(0\)位置,顯然還要動\(L-1\)次,如果不包含\(0\)位置,顯然要先把\(0\)位置弄進這個環裏面來,再把它移出去,也就是\(L+1\)次。那麽我們就可以很容易的計算答案。
然而現在最大的難題變成了如何計算最終位置了。
對於每個位置,我們不難發現隨著\(x\)的增大,關於\(n\)的余數一定是一個個的環。那麽我們考慮枚舉\(y\)
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<vector> using namespace std; #define ll long long #define MAX 100100 inline int read() { int x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } int C[MAX],pos[MAX]; int n,S,Q,P,M,D; int f[MAX];bool vis[MAX]; int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);} void merge(int u,int v){f[getf(u)]=getf(v);} int main() { int T=read(); while(T--) { n=read();S=read();Q=read();P=read();M=read();D=read(); for(int i=1;i<n;++i)C[i]=(1ll*C[i-1]*Q+P)%M; for(int i=0;i<n;++i)f[i]=i; memset(vis,0,sizeof(vis)); pos[0]=S;vis[S]=true;merge(S,(S+D)%n); for(int i=1;i<n;++i) { int x=getf(C[i]%n),y=0; while(vis[x])++y,x=getf((C[i]+y)%n); pos[i]=x;vis[x]=1;merge(x,(x+D)%n); } memset(vis,0,sizeof(vis));int ans=0,gr=0; for(int i=0;i<n;++i) if(!vis[i]) { int tot=0,u=i; while(!vis[u])++tot,vis[u]=true,u=pos[u]; if(tot>1)ans+=tot,++gr; } if(!pos[0])ans+=gr;else ans+=gr-2; printf("%d\n",ans); } return 0; }
【BZOJ1998】[HNOI2010]物品調度(並查集,模擬)