2023.02.20【省选组】模拟 总结
又是写暴力的一天
发现自己连 都不会了
考场暴力都写不出来的原因:不知如何计算各个环长确定的情况下对应排列的数目
因为没有逆元,没法直接排列组合计数。。。
关键在于如果存在环长相同的情况,直接计数不可避免要除掉相同环长数量的阶乘
然而可以 计数,考场想了一会却不会
考虑一个环的代表为这个环上最小的数,那么枚举当前最小值所在环的大小转移,这样就可以避免算重了
这道题又是 相关的计数
考虑单独拆开算每个质因子的指数,对某个质因子而言计算 的排列数量
改成计算 的排列数量,那么环中只要至少存在一个 倍数的环即可
补集思想,计数不存在一个环长为 倍数的排列数
若长度为 ,这个数目记为 ,那么
表示长度为 的排列环长均为 的倍数的排列数目
于是就可以 了
加法运算整个式子的类型默认为第一个对象的类型
#include <bits/stdc++.h> #define IN inline using namespace std; typedef long long LL; const int N = 7505; int b[N], n, M, P, C[N][N], bz[N]; IN void Add(LL &x, int y){if ((x += y) >= P) x -= P;} int fpow(int x, int y, int p) { int s = 1; for(; y; y >>= 1, x = (LL)x * x % p) if (y & 1) s = (LL)s * x % p; return s; } LL f[N], g[N], fac[N]; IN int calc(int x) { g[0] = 1; for(int i = x; i <= n; i += x) { g[i] = 0; for(int j = x; j <= i; j += x) Add(g[i], g[i - j] * C[i - 1][j - 1] % P * fac[j - 1] % P); } f[0] = 1; for(int i = n % x; i <= n; i += x) { f[i] = fac[i]; for(int j = x; j <= i; j += x) Add(f[i], P - g[j] * C[i][j] % P * f[i - j] % P); } return (fac[n] - f[n] + P) % P; } int main() { freopen("exercise.in", "r", stdin); freopen("exercise.out", "w", stdout); scanf("%d%d", &n, &M), P = M - 1, fac[0] = 1; for(int i = 1; i <= n; i++) fac[i] = fac[i - 1] * i % P; for(int i = 0; i <= n; i++) C[i][0] = 1; for(int i = 1; i <= n; i++) for(int j = 1; j <= i; j++) { LL z = C[i - 1][j]; Add(z, C[i - 1][j - 1]); C[i][j] = z; } int ans = 1; for(int i = 2; i <= n; i++) if (!bz[i]) { for(int j = i * i; j <= n; j += i) bz[j] = 1; for(int j = i; j <= n; j *= i) ans = (LL)ans * fpow(i, calc(j), M) % M; } printf("%d\n", ans); }
仙姑了。。。
在 意义下是有个循环节的,且比较短,和斐波那契数列循环节一样
找到这个循环节即可,然后就是套路矩乘了
函数定义的 不能漏,本地编译却可通过
#include <bits/stdc++.h> #define IN inline using namespace std; template <typename Tp> IN void read(Tp &x) { x = 0; char ch = getchar(); int f = 0; for(; !isdigit(ch); f = (ch == '-' ? 1 : f), ch = getchar()); for(; isdigit(ch); x = (x<<3)+(x<<1)+(ch^48), ch = getchar()); if (f) x = ~x + 1; } typedef long long LL; LL P, pk[105]; LL gcd(LL x, LL y){return (!y ? x : gcd(y, x % y));} struct Matrix { LL s00, s01, s10, s11; IN Matrix(LL a0 = 0, LL a1 = 0, LL a2 = 0, LL a3 = 0){s00 = a0, s01 = a1, s10 = a2, s11 = a3;} IN Matrix operator * (const Matrix &B) { Matrix C; C.s00 = (s00 * B.s00 % P + s01 * B.s10 % P) % P; C.s01 = (s00 * B.s01 % P + s01 * B.s11 % P) % P; C.s10 = (s10 * B.s00 % P + s11 * B.s10 % P) % P; C.s11 = (s10 * B.s01 % P + s11 * B.s11 % P) % P; return C; } }Z, I, B; IN Matrix fpow(Matrix x, LL y) { Matrix s = I; for(; y; y >>= 1, x = x * x) if (y & 1) s = s * x; return s; } IN int find(int x) { if (x == 2) return 3; if (x == 3) return 4; if (x == 5) return 10; if (x % 5 == 1 || x % 5 == 4) return x - 1; return x + 1; } IN LL calc(LL p) { LL lcm = 1; for(LL i = 2; i * i <= p; i++) if (p % i == 0) { LL w = 1; while (p % i == 0) p /= i, w *= i; w /= i, w = w * find(i), lcm = lcm / gcd(lcm, w) * w; } if (p > 1) p = find(p), lcm = lcm / gcd(lcm, p) * p; return lcm; } int main() { freopen("hakugai.in", "r", stdin); freopen("hakugai.out", "w", stdout); int t; read(t); I = Matrix(1, 0, 0, 1); for(; t; --t) { int a, b, p, k; LL n; read(a), read(b), read(n), read(k), read(p); pk[1] = p; for(int i = 2; i <= k; i++) pk[i] = calc(pk[i - 1]); for(Matrix ret; k; k--) { P = pk[k], Z = Matrix(a % P, b % P, 0, 0), B = Matrix(0, P - 1, 1, 3); ret = Z * fpow(B, n), n = ret.s00; } printf("%lld\n", n); } }
这个循环节的计算规律是真不可背诵的
不过可以随机化,依据生日悖论寻找,
具体来说就是猜测最小循环节上界,大致猜个
然后在这个范围内随机个 ,看算出的 是否与之前重复
若是,重复的为 ,那么一定有个循环节
期望 次可以找到
下面是 斐波那契数列
交了三遍才过呢
#include <bits/stdc++.h> #define IN inline using namespace std; typedef long long LL; typedef unsigned long long ull; LL P; struct Matrix { LL s00, s01, s10, s11; IN Matrix(LL a0 = 0, LL a1 = 0, LL a2 = 0, LL a3 = 0){s00 = a0, s01 = a1, s10 = a2, s11 = a3;} IN Matrix operator * (const Matrix &B) { Matrix C; C.s00 = (s00 * B.s00 % P + s01 * B.s10 % P) % P; C.s01 = (s00 * B.s01 % P + s01 * B.s11 % P) % P; C.s10 = (s10 * B.s00 % P + s11 * B.s10 % P) % P; C.s11 = (s10 * B.s01 % P + s11 * B.s11 % P) % P; return C; } }I, B; const int M = 1 << 18; struct KSM { Matrix f[M + 5], ff[M + 5]; IN void init(int m) { f[0] = ff[0] = I; for(int i = 1; i <= m; i++) f[i] = f[i - 1] * B; for(int i = 1; i <= m; i++) ff[i] = ff[i - 1] * f[m]; } IN Matrix pow(LL x){return f[x & (M - 1)] * ff[x >> 18];} }F; const int N = 3e7 + 5; char str[N]; mt19937_64 rnd(time(0)); unordered_map<ull, LL> hs; int main() { scanf("%s%d", str, &P), I = Matrix(1, 0, 0, 1), B = Matrix(0, 1, 1, 1), F.init(M); LL len = 0; while (1) { LL x = (rnd() << 28 >> 28); Matrix C = F.pow(x); ull val = ((ull)C.s00 << 32) | C.s01; if (hs.find(val) != hs.end()){len = abs(x - hs[val]); break;} hs[val] = x; } LL z = 0; for(int i = 0; i < strlen(str); i++) z = (z * 10 + (str[i] ^ 48)) % len; printf("%lld\n", F.pow(z).s01); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
2020-02-20 子集选取
2020-02-20 【SDOI2015】星际战争
2020-02-20 【SDOI2015】寻宝游戏
2020-02-20 【SDOI2015】排序
2020-02-20 【雅礼联考DAY02】Revolution
2020-02-20 【雅礼联考DAY02】Magic
2020-02-20 【雅礼联考DAY01】逃跑