题意

洗牌游戏。初始顺序为 1~n1~n1~n,AliceAliceAlice 与 BobBobBob 轮流操作此牌堆。AliceAliceAlice 操作时会将位置 iii 上的牌移到 a[i]a[i]a[i] 上;BobBobBob 操作时会将位置 iii 上的牌移到 b[i]b[i]b[i] 上,问最少移动多少次桌上的牌会恢复原状,若 101210^{12}1012 次内无法还原,则输出 hugehugehuge。(1≤n≤105)(1\leq n\leq 10^5)(1≤n≤105)


思路

首先一个很明显的思路,对结束点的分类枚举,即该游戏可能结束于 AliceAliceAlice,也可能结束于 BobBobBob。

若结束于 BobBobBob,则可以将 AliceAliceAlice 和 BobBobBob 的两个操作合成一个操作,然后问最少多少步可以还原。此时答案比较好求,即先求出游戏中的多个循环节,各个循环节长度的最小公倍数即为答案。

若结束于 AliceAliceAlice,则修改每一个点的结束位置,因此对于每个循环节来说,最少操作次数应为 k∗T[i]+mod[i]k*T[i]+mod[i]k∗T[i]+mod[i],其中 kkk 为任意非负整数,T[i]T[i]T[i] 为该循环节的长度,mod[i]mod[i]mod[i] 表示该循环节中的节点距离其目标节点的最短距离。

因此我们可以发现最终的答案需要求解一个同余方程组,因此使用中国剩余定理进行求解。

比赛时思路就已经到达了此步,但仍然无论如何都无法 ACACAC,主要有两个原因:

  1. 中国剩余定理板子不够优秀(大数据无法处理)
  2. 计算过程爆 longlonglong longlonglong 了,用 __int128\_\_int128__int128 也不行,最后改写成 pythonpythonpython 后通过

反思

一道题怼的太久,导致错失了 ACACAC 其他题的可能性。除此之外,数论方面的板子过于陈旧,今后遇到数论题需要主动承担不能逃避。最后,中国剩余定理存在爆 longlonglong longlonglong 的可能,需要及时反应过来并将其换成 pythonpythonpython 或 javajavajava。


代码

cppcppcpp 代码,最后两个测试点无法通过。

#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof a);
#define rep(i,a,b) for(ll i = a; i <= b; i++)
#define per(i,a,b) for(ll i = a; i >= b; i--)
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define ll __int128
typedef double db;
const db EPS = 1e-9;
const int N = 1e5+100;
const ll inf = 1e17;
using namespace std;void dbg() {cout << "\n";}
template<typename T, typename... A> void dbg(T a, A... x) {cout << a << ' '; dbg(x...);}
#define logs(x...) {cout << #x << " -> "; dbg(x);}// tot 个循环结,T[i] 每个循环节长度
// vis[i] 第 i 个点所在循环节位置
ll n,a[N],b[N],c[N],tot,vis[N];
ll T[N], mod[N], m[N];void init(){rep(i,1,n) c[i] = b[a[i]];rep(i,1,n){if(vis[i]) continue;ll tmp = c[i], len = 1;while(tmp != i){tmp = c[tmp];len++;}T[++tot] = len;vis[i] = tot; tmp = c[i];while(tmp != i){vis[tmp] = tot;tmp = c[tmp];}}
}ll gcd(ll a, ll b){return b == 0 ? a : gcd(b, a%b);
}ll solve1(){ll ans = T[1];rep(i,2,tot){ans = ans * T[i] / gcd(ans, T[i]);if(ans > 1e12) return 1e13;}return ans * 2ll;
}ll exgcd(ll a, ll b, ll &x, ll &y) {if (b == 0) {x = 1, y = 0; return a;}ll r = exgcd(b, a % b, x, y), tmp;tmp = x; x = y; y = tmp - (a / b) * y;return r;
}
ll inv(ll a, ll b) {ll x = 0, y = 0;ll r = exgcd(a, b, x, y);while (x < 0) x += b;return x;
}
ll excrt(ll n, ll M[], ll C[]){ // % m = cfor (ll i = 2; i <= n; i++) {ll M1 = M[i - 1], M2 = M[i], C2 = C[i], C1 = C[i - 1], T = gcd(M1, M2);if ((C2 - C1) % T != 0) return 1e13;M[i] = (M1 * M2) / T;C[i] = ( inv( M1 / T , M2 / T ) * (C2 - C1) / T ) % (M2 / T) * M1 + C1;C[i] = (C[i] % M[i] + M[i]) % M[i];if(C[i] > 1e12) return 1e13;}return C[n];
}ll tt[N];ll solve2(){rep(i,1,n) tt[i] = a[i];rep(i,1,n) a[tt[i]] = i;rep(i,1,n) m[i] = inf;rep(i,1,n){if(m[i] != inf) continue;if(vis[a[i]] != vis[i]) return 1e13;else{ll len = 0, tmp = i;while(tmp != a[i]){tmp = c[tmp];len++;}m[i] = len;ll p1 = c[i], p2 = c[a[i]];while(p1 != i){if(a[p1] != p2) return 1e13;else m[p1] = len;p1 = c[p1];p2 = c[p2];}}}rep(i,1,n) mod[i] = inf;rep(i,1,n)if(m[i] == T[vis[i]]) m[i] = 0;rep(i,1,n){if(mod[vis[i]] == inf) mod[vis[i]] = m[i];else if(mod[vis[i]] != m[i]) return 1e13;}return (excrt(tot,T,mod) * 2ll + 1ll);
}inline __int128 read() {__int128 x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}return x*f;
}inline void write(__int128 x) {if(x<0) { putchar('-'); x=-x; }if(x>9) write(x/10);putchar(x%10+'0');
}int main()
{n = read();rep(i,1,n) a[i] = read();rep(i,1,n) b[i] = read();ll ans = 1e13;init();ll tp = solve1();if(tp > 0) ans = min(ans,tp);tp = solve2();if(tp > 0) ans = min(ans,tp);if(ans > 1e12) printf("huge");else write(ans);return 0;
}

改写成 pythonpythonpython 代码后,可以通过全部测试点。

inf, N = int(1e17), int(100100)
# tot 个循环结,T[i] 每个循环节长度
# vis[i] 第 i 个点所在循环节位置
n, a, b, c, tot, vis = 0, [0], [0], [0]*N, 0, [0]*N
T, mod, m, tt, tmp, len = [0]*N, [0]*N, [0]*N, [0]*N, 0, 0def init():global n, a, b, c, tot, vis, T, mod, m, tt, inf, N, tmp, lenfor i in range(1, n+1):c[i] = b[a[i]]for i in range(1, n+1):if vis[i] != 0:continuetmp, len = c[i], 1while tmp != i:tmp = c[tmp]len += 1tot += 1T[tot] = lenvis[i] = tottmp = c[i]while tmp != i:vis[tmp] = tottmp = c[tmp]def gcd(a, b):if b == 0:return aelse:return gcd(b, a % b)def solve1():global n, a, b, c, tot, vis, T, mod, m, tt, inf, Nans = 0ans = T[1]for i in range(2, tot+1):ans = ans * T[i] / gcd(ans, T[i])if ans > 1e12:return int(1e13)return ans * int(2)def exgcd(a, b, x, y):re, tmp = 0, 0if b == 0:return a, 1, 0re, x, y = exgcd(b, a % b, x, y)tmp = xx = yy = tmp - (a//b)*yreturn re, x, ydef inv(a, b):x, y, r = 0, 0, 0r, x, y = exgcd(a, b, x, y)while x < 0:x += breturn xdef excrt(n, M, C):M1, M2, C1, C2, T = 0, 0, 0, 0, 0for i in range(2, n+1):M1, M2, C1, C2 = M[i-1], M[i], C[i-1], C[i]T = gcd(M1, M2)if (C2-C1) % T != 0:return 1e13M[i] = (M1 * M2) // TC[i] = (inv(M1//T, M2//T) * (C2-C1) // T) % (M2 // T) * M1 + C1C[i] = (mod[i] % M[i] + M[i]) % M[i]if C[i] > 1e12:return 1e13return C[n]def solve2():global n, a, b, c, tot, vis, T, mod, m, tt, inf, N, tmp, lenfor i in range(1, n+1):tt[i] = a[i]for i in range(1, n+1):a[tt[i]] = ifor i in range(1, n+1):m[i] = inffor i in range(1, n+1):if m[i] != inf:continueif vis[a[i]] != vis[i]:return int(1e13)else:tmp = 0len, tmp, p1, p2 = 0, i, 0, 0while tmp != a[i]:tmp = c[tmp]len += 1m[i] = lenp1, p2 = c[i], c[a[i]]while p1 != i:if a[p1] != p2:return int(1e13)else:m[p1] = lenp1 = c[p1]p2 = c[p2]for i in range(1, n+1):mod[i] = inffor i in range(1, n+1):if m[i] == T[vis[i]]:m[i] = 0for i in range(1, n+1):if mod[vis[i]] == inf:mod[vis[i]] = m[i]elif mod[vis[i]] != m[i]:return int(1e13)return excrt(tot, T, mod) * 2 + 1def main():global n, a, b, c, tot, vis, T, mod, m, tt, inf, Nn = int(input())a.extend(list(map(int, input().split())))b.extend(list(map(int, input().split())))ans = int(1e13)init()ans = min(ans, solve1())ans = min(ans, solve2())if ans > 1e12:print("huge")else:print(int(ans))if __name__ == "__main__":main()

后记

场上自闭 2h2h2h,场下自闭 5h5h5h,真实自闭题…

不过不得不说,好久没这么自闭调题了,ACACAC 的那一刻的确是直接跳起来了,久违的感觉!

最后,请务必继续奔跑,追逐属于自己的那束光!

【2019 BAPC - D】Deck Randomisation【中国剩余定理 + 循环节】相关推荐

  1. 2019牛客暑期多校训练营(第九场)A——The power of Fibonacci(循环节+中国剩余定理(互质)||广义BM)

    链接:https://ac.nowcoder.com/acm/contest/889/A 来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262144K,其他语言5242 ...

  2. 解题报告(十三)中国剩余定理(ACM / OI)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量的题解和代码,题目难度不一 ...

  3. 礼物(中国剩余定理+拓展gcd求逆元+分治=拓展Lucus)

    礼物 题意: 求\[C(n,m)\ \%\ p\] \(n,m,p\le 10^9\),且若\(p=\prod_{i=1}^{k}{p_i}^{c_i}\),则\(\forall i\in [1..k ...

  4. 游乐园(中国剩余定理)

    游乐园 时间限制: 1 Sec 内存限制: 128 MB 题目描述 今天是个好日子,小A和他的小伙伴们一起去逛游乐园.这时,游乐园中忽然出现了一个伪装的吸血鬼,小A和他的小伙伴们都惊呆了!小伙伴们马上 ...

  5. 中国剩余定理(孙子定理)的证明和c++求解

    <孙子算经>里面的"物不知数"说的是这样的一个题目:一堆东西不知道具体数目,3个一数剩2个,5个一数剩3个,7个一数剩2个,问一共有多少个. 书里面给了计算过程及答案: ...

  6. 中国剩余定理(Chinese Remainder Theorem)

    中国剩余定理 民间传说着一则故事--"韩信点兵". 秦朝末年,楚汉相争.一次,韩信将1500名将士与楚王大将李锋交战.苦战一场,楚军不敌,败退回营,汉军也死伤四五百人,于是韩信整顿 ...

  7. 【中国剩余定理】POJ 1006 HDU 1370 Biorhythms

    题目链接: http://poj.org/problem?id=1006 http://acm.hdu.edu.cn/showproblem.php?pid=1370 题目大意: (X+d)%23=a ...

  8. 中国剩余定理matlab非互质,中国剩余定理模板(互质版和非互质版)

    互质版: #include #include #include using namespace std; typedef __int64 int64; int64 a[15],b[15]; int64 ...

  9. POJ2891 Strange Way to Express Integers【扩展中国剩余定理】

    题目大意 就是模板...没啥好说的 思路 因为模数不互质,所以直接中国剩余定理肯定是不对的 然后就考虑怎么合并两个同余方程 \(ans = a_1 + x_1 * m_1 = a_2 + x_2 * ...

  10. 韩信点兵-中国剩余定理(练习)

    http://acm.nyist.net/JudgeOnline/problem.php?pid=34提交地址 韩信点兵-中国剩余定理. 题目能够用枚举非常easy的做出来,在这里写是为了运用一下刚刚 ...

最新文章

  1. CTFshow 命令执行 web77
  2. java基础第十四天_IO
  3. javascript的全局变量
  4. Java多线程——FutureTask源码解析
  5. 经常使用的webservice接口
  6. python启动http服务_Python通过命令开启http.server服务器的方法
  7. 阿里巴巴公布了一份最新的AI成绩单
  8. 区块链软件:区块链的迅猛发展
  9. Android安卓备份还原
  10. 十分详细的React入门实例
  11. 脱壳--00.aspack.exe
  12. java close 方法,close()方法的用法(Java初学者)
  13. word添加引用及自动更新的方法
  14. 第一博客,行走在编程道路上的菜鸟
  15. 拼多多618手机品牌官旗销量同比增长124%,4000+高价位手机同比增长156%
  16. Microsoft Office 2007不能安装的原因
  17. Flexigrid在FleaPHP下的使用方法介绍
  18. java 并发xmind_多线程+高并发+操作系统+网络+基础+调优+源码等xmind图整理好了
  19. 移动端界面中的版式设计原理(上)
  20. Adobe Premiere基础-工具使用(选择工具,剃刀工具,等常用工具)(三)

热门文章

  1. Yarn 调度器Scheduler详解
  2. 三目运算符?:结合性
  3. linux 后台进程管理,Linux 后台进程管理利器 Supervisor
  4. 博弈论——Nim游戏
  5. html添加变量参数吗,动态CSS与变量参数? (可能吗?)
  6. 未来的工作都被计算机代替,未来10年,50%的工作将被机器取代?而这些职业却无法被取代...
  7. php源码修改器,php之0525获取器、修改器、验证
  8. java foreach 赋值_java foreach 使用
  9. 英文文本处理 c github_真香警告!有了这个搜索大法,GitHub可以玩到飞起来!
  10. 3台机器配置hadoop集群_复制Hadoop集群之后无法访问端口50070的问题