[BZOJ1998][Hnoi2010]Fsk物品调度
[BZOJ1998][Hnoi2010]Fsk物品调度
试题描述
现在找工作不容易,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最小的。 这样你得到了所有盒子的最终位置,现在你每次可以把某个盒子移动到空位上,移动后原盒子所在的位置成为空位。请问把所有的盒子移动到目的位置所需的最少步数。
输入
第一行包含一个整数t,表示数据组数。接下来t行,每行6个数,n,s,q,p,m,d意义如上所述。 对于30%的数据n<=100,对于100%的数据t<=20,n<=100000,s
输出
对于每组数据输出一个数占一行,表示最少移动步数。
输入示例
输出示例
数据规模及约定
t<=20,n<=100000
题解
刚刚在火车上调出了这道题。。。
关键在于如何求 pos 数组,不难发现式子中 d 是固定的,所以 xi 每增加 1,posi 就要增加 d,而 yi 每增加 1,posi 会增加 1.
再看看题目要求优先考虑令 yi 最小,即,固定 yi,改变 xi.假设我们已经把 yi 固定下来了,则可以将 1~n 的数按照对 d 取余得到的余数分类,通过 ci 和固定下来的 yi 的值确定要找的数在哪类,选取没有被选过的且离 ci “向右距离”(从 ci 出发向右走,遇到 n 就回到 0,继续向右到达该数所需的步数)最近的那个数就行了,可以用个并查集实现。那么如何固定 yi 呢?类似地,也可以对于每一类数建立一个并查集,当某一类数都被选取后,将该节点与左右合并,查找时找没有满的且离 yi + ci 所属的类“向右距离”最近的一类即可。
最后求步数不妨放自己yy。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; #define maxn 100010
#define LL long long
int n, s, q, p, m, d, gcdnd, pos[maxn];
bool has[maxn], h2[maxn]; int fa[maxn], siz[maxn];
int findset(int x) { return x == fa[x] ? x : fa[x] = findset(fa[x]); }
int f2[maxn];
int find2(int x) { return x == f2[x] ? x : f2[x] = find2(f2[x]); }
int nxt(int x) { return (x + d) % n; }
int pre(int x) { return (x - d + n) % n; }
LL gcd(LL a, LL b) { return !b ? a : gcd(b, a % b); }
void add(int u, int x) {
has[u] = 1;
int v = findset(nxt(u));
if(has[v]) fa[u] = v;
v = findset(pre(u)); u = findset(u);
if(u != v) { if(has[v]) fa[v] = u; }
else {
h2[x] = 1; int xx = find2(x);
if(x < gcdnd - 1 && h2[x+1]){ v = find2(x + 1); if(x != v) f2[x] = v; }
if(x && h2[x-1]){ v = find2(x - 1); if(x != v) f2[v] = x; }
}
return ;
} int main() {
int T; scanf("%d", &T);
while(T--) {
scanf("%d%d%d%d%d%d", &n, &s, &q, &p, &m, &d); d %= n;
// n = read(); s = read(); q = read(); p = read(); m = read(); d = read() % n;
gcdnd = gcd(n, d);
memset(has, 0, sizeof(has));
memset(h2, 0, sizeof(h2));
has[s] = 1;
for(int i = 0; i < n; i++) fa[i] = i;
for(int i = 0; i < gcdnd; i++) f2[i] = i;
LL c = 0;
for(int i = 1; i < n; i++) {
c = (c * q + p) % m;
LL cd = c % n % gcdnd;
int y = find2(cd); if(h2[y]) y++; if(y >= gcdnd){ y = find2(0); if(h2[y]) y++; }
int u;
if(y - cd >= 0){ u = findset((c % n + y - cd) % n); if(has[u]) u = nxt(u); }
else { u = findset((c % n + y - cd + gcdnd) % n); if(has[u]) u = nxt(u); }
add(u, y); pos[i] = u;
} // for(int i = 1; i < n; i++) printf("%d ", pos[i]); puts("\n");
for(int i = 0; i < n; i++) fa[i] = i, siz[i] = 1;
for(int i = 1; i < n; i++) {
int u = findset(i), v = findset(pos[i]);
if(u != v) fa[v] = u, siz[u] += siz[v], siz[v] = 0;
}
for(int i = 0; i < n; i++) pos[i] = findset(i);
sort(pos, pos + n);
int ans = 0;
for(int i = 0; i < n; i++) if((!i || pos[i] != pos[i-1]) && siz[pos[i]] > 1) ans += siz[pos[i]] + 1;
if(siz[findset(0)] > 1) ans -= 2;
printf("%d\n", ans);
} return 0;
}
[BZOJ1998][Hnoi2010]Fsk物品调度的更多相关文章
- 【BZOJ 1998】 1998: [Hnoi2010]Fsk物品调度(双向链表+并查集+置换)
1998: [Hnoi2010]Fsk物品调度 Description 现在找工作不容易,Lostmonkey费了好大劲才得到fsk公司基层流水线操作员的职位.流水线上有n个位置,从0到n-1依次编号 ...
- BZOJ_1998_[Hnoi2010]Fsk物品调度_并查集+置换
BZOJ_1998_[Hnoi2010]Fsk物品调度_并查集+置换 Description 现在找工作不容易,Lostmonkey费了好大劲才得到fsk公司基层流水线操作员的职位.流水线上有n个位置 ...
- 【BZOJ】1998: [Hnoi2010]Fsk物品调度
http://www.lydsy.com/JudgeOnline/problem.php?id=1998 题意: 给你6个整数$n,s,q,p,m,d$. 有$n$个位置和$n-1$个盒子,位置编号从 ...
- BZOJ 1998: [Hnoi2010]Fsk物品调度 [置换群 并查集]
传送门 流水线上有n个位置,从0到n-1依次编号,一开始0号位置空,其它的位置i上有编号为i的盒子.Lostmonkey要按照以下规则重新排列这些盒子. 规则由5个数描述,q,p,m,d,s,s表示空 ...
- 【BZOJ 1998】[Hnoi2010]Fsk物品调度 置换群+并查集
置换群的部分水得一比,据说是经典的置换群理论(然而我并不知道这理论是啥).重点就在于怎么求pos!!!容易发现这个东西是这样的:每次寻找pos,先在本环里找,找不到再往下一个环里找,直到找到为止……一 ...
- 【BZOJ1998】[HNOI2010]物品调度(并查集,模拟)
[BZOJ1998][HNOI2010]物品调度(并查集,模拟) 题面 BZOJ,为啥这题都是权限题啊? 洛谷 题解 先不管\(0\)位置是个空,把它也看成一个箱子.那么最终的答案显然和置换循环节的个 ...
- [HNOI2010] 物品调度 fsk
标签:链表+数论知识. 题解: 对于这道题,其实就是两个问题的拼凑,我们分开来看. 首先要求xi与yi.这个可以发现,x每增加1,则pos增加d:y每增加1,则pos增加1.然后,我们把x与y分别写在 ...
- [HNOI2010]物品调度
题目描述 现在找工作不容易,Lostmonkey费了好大劲才得到fsk公司基层流水线操作员的职位.流水线上有n个位置,从0到n-1依次编号,一开始0号位置空,其它的位置i上有编号为i的盒子.Lostm ...
- P3207 [HNOI2010]物品调度
传送门 完了题目看错了--还以为所有的\(x,y\)都要一样--结果题解都没看懂-- 先考虑如果已经求出了所有的\(pos\)要怎么办,那么我们可以把\(0\)也看做是一个箱子,然后最后每个箱子都在一 ...
随机推荐
- 第三十九课:requestAnimationFrame详解
大家应该都知道,如果一个页面运行的定时器很多,无论你怎么优化,最后肯定会超过指定时间才能完成动画.定时器越多,延时越严重. 为此,YUI,kissy等采用中央队列的方式,将定时器减少至一个.浏览器厂商 ...
- 每天一个linux命令(42):crontab命令
前 一天学习了 at 命令是针对仅运行一次的任务,循环运行的例行性计划任务,linux系统则是由 cron (crond) 这个系统服务来控制的. Linux 系统上面原本就有非常多的计划性工作,因此 ...
- OC基础--OC中类的定义
OC中类的定义与使用跟C#和java差别相当明显,做个笔记,牢记并加以区别! 一.OC中类的定义:关键字@implementation 和 @end 注意事项: 1.定义好一个类之后,要让这个类继承N ...
- 【BZOJ 3196】二逼平衡树 线段树套splay 模板题
我写的是线段树套splay,网上很多人写的都是套treap,然而本蒟蒻并不会treap 奉上sth神犇的模板: //bzoj3196 二逼平衡树,支持修改某个点的值,查询区间第k小值,查询区间某个值排 ...
- java.lang.NoClassDefFoundError: javax/transaction/UserTransaction
在运行定时任务的时候报错: Java.lang.NoClassDefFoundError: javax/transaction/UserTransaction 原因:缺少jta的jar包 解决方法:下 ...
- 处理Json数据中的日期类型.如/Date(1415169703000)/格式
在asp.net mvc后台返回到视图中的json数据中想对数据进行操作,发现日期类型无法直接进行操作,需要转换为指定格式才行.在网上也搜了下方法也很多,觉得有点麻烦,最终使用正则搞定了,分享下: v ...
- LinkedHashMap实现LRU算法
LinkedHashMap特别有意思,它不仅仅是在HashMap上增加Entry的双向链接,它更能借助此特性实现保证Iterator迭代按照插入顺序(以insert模式创建LinkedHashMap) ...
- 【BZOJ】【1009】 【HNOI2008】GT考试
DP/KMP/矩阵乘法 好神的题啊……跪了跪了 $n\leq 10^9$是什么鬼……我们还是先不要考虑这个鬼畜的玩意了>_> 用类似数位DP的思路,我们可以想到一个DP方程:$f[i][j ...
- USACO 3.3 fence 欧拉回路
题意:求给定图的欧拉回路(每条边只走一次) 若欧拉回路存在,图中只可能有0个or2个奇数度的点. 求解时,若有奇数度的点,则必须从该点开始.否则可以从任一点开始 求解过程:dfs //主程序部分 # ...
- 内部类访问局部变量的时候,为什么变量必须加上final修饰
这里的局部变量就是在类方法中的变量,能访问方法中变量的类当然也是局部内部类了.我们都知道,局部变量在所处的函数执行完之后就释放了,但是内部类对象如果还有引用指向的话它是还存在的.例如下面的代码: cl ...