NFLS 数学专题
B. [WC2021] 斐波那契
题目描述
众所周知,小葱同学擅长计算,尤其擅长计算组合数。但是对组合数有了充分研究的小葱同学对组合数失去了兴趣,而开始研究数列。
我们定义
现在给定
输入格式
第一行两个整数
接下来
输出格式
对于每组询问,输出一行一个整数 -1
。
样例 #1
样例输入 #1
4 5
0 1
1 2
2 3
3 4
样例输出 #1
0
3
2
-1
样例 #2
样例输入 #2
1 6
4 4
样例输出 #2
3
样例 #3
样例输入 #3
见附件中的 fib/fib3.in
样例输出 #3
见附件中的 fib/fib3.ans
样例 #4
样例输入 #4
见附件中的 fib/fib4.in
样例输出 #4
见附件中的 fib/fib4.ans
提示
【数据范围】
对于所有测试点:
每个测试点的具体限制见下表:
测试点编号 | 特殊限制 | |
---|---|---|
无 | ||
无 |
题解
首先,斐波那契数列在模特判掉
置
这对我们的思路有一定的启发,当
为了将
现在我们想要把
于是我们可以放心地移项变为
预处理时枚举
注意到最后一步移项中我们保证了
因此预处理时只需要枚举
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, m;
inline int Plus(int a, int b, const int mod = m) {return a + b >= mod ? a + b - mod : a + b; }
inline int Minus(int a, int b, const int mod = m) {return a - b < 0 ? a - b + mod : a - b; }
void exgcd(int a, int b, int &d, int &x, int &y) {
if(!b) {d = a, x = 1, y = 0; return; }
exgcd(b, a % b, d, y, x);
y -= (a / b) * x;
}
inline int inv(int a, const int mod) {
int d, x, y;
exgcd(a, mod, d, x, y);
assert(d == 1);
return (x % mod + mod) % mod;
}
map<tuple<int, int, int>, int> Map;
int f[N * 6];
inline void init() {
f[1] = 1;
for(int d = 1; d < m; d ++) {
if(m % d) continue;
const int mod = m / d;
for(int p = 2; ; p ++) {
f[p] = Plus(f[p - 1], f[p - 2], mod);
if(f[p - 1] == 0 && f[p] == 1) break;
if(f[p - 1] == 0 || f[p] == 0) continue;
int d1 = __gcd(f[p - 1], mod);
int val = 1ll * f[p] * inv(f[p - 1] / d1, mod / d1) % (mod / d1);
if(!Map.count({d, d1, val}))
Map[{d, d1, val}] = p;
}
}
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
cin >> n >> m;
init();
while(n --) {
int a, b; cin >> a >> b;
if(a && b) {
b = Minus(0, b);
int d = __gcd(m, __gcd(a, b));
int d1 = __gcd(b / d, m / d);
int val = 1ll * a / d * inv(b / d / d1, m / d / d1) % (m / d / d1);
if(Map.count({d, d1, val})) cout << Map[{d, d1, val}] << '\n';
else cout << "-1" << '\n';
} else cout << (a == 0 ? "0" : "1") << '\n';
}
return 0;
}
D. [COCI2012-2013#6] BAKTERIJE
题目描述
一个
给定所有信息,求什么时候所有细菌被消灭。
输入格式
第一行三个正整数
接下来一行,两个数
接下来依次描述每一个细菌:
- 首先是一行两个数
和一个字母 ,分别表示行列坐标和它的方向,U
表示上,D
表示下,L
表示左,R
表示右。 - 接下来一个矩阵,表示这个细菌在这个每一个单元格上的
, 。
输出格式
一行一个数,表示细菌被杀死的最后时间,如果无法全部消灭则输出
样例 #1
样例输入 #1
3 3 1
2 2
1 1 R
010
000
000
样例输出 #1
3
样例 #2
样例输入 #2
3 4 2
2 2
3 4 R
2327
6009
2112
3 2 R
1310
2101
1301
样例输出 #2
8
样例 #3
样例输入 #3
4 4 3
4 3
1 1 U
1001
0240
3322
2327
1 3 L
9521
2390
3020
2421
2 2 D
3397
2013
1102
7302
样例输出 #3
296
提示
题解
注意到先模拟
#include <bits/stdc++.h>
using namespace std;
ostream& operator << (ostream &out, __int128 x) {
if(x < 0) out << '-', x = -x;
stack<int> stk;
do {stk.push(x % 10); x /= 10; } while(x);
while(!stk.empty()) {out << stk.top(); stk.pop(); }
return out;
}
struct node {
int x, y, dir;
/*
1
0 x 2
3
*/
};
bool operator == (const node &lhs, const node &rhs) {
return lhs.x == rhs.x && lhs.y == rhs.y && lhs.dir == rhs.dir;
}
int dx[] = {0, -1, 0, 1}, dy[] = {-1, 0, 1, 0};
inline int get(char c) {
if(c == 'L') return 0;
if(c == 'U') return 1;
if(c == 'R') return 2;
if(c == 'D') return 3;
assert(false); return -1;
}
const int N = 55;
int n, m, k, trap_x, trap_y;
node S[6], pos[6];
char G[10][N][N];
inline node go(node u, int id) {
u.dir = (u.dir + (G[id][u.x][u.y] - '0')) % 4;
if(u.x + dx[u.dir] == 0 || u.y + dy[u.dir] == 0 || u.x + dx[u.dir] > n || u.y + dy[u.dir] > m)
u.dir = (u.dir + 2) % 4;
u.x += dx[u.dir], u.y += dy[u.dir];
return u;
}
inline bool check() {
for(int i = 0; i < k; i ++)
if(pos[i].x != trap_x || pos[i].y != trap_y) return false;
return true;
}
int dep[N][N][4], chain_len[6], circle_len[6], A[6][4];
inline void calc(int u) {
memset(dep, -1, sizeof dep);
int depth = 0;
while(true) {
if(dep[pos[u].x][pos[u].y][pos[u].dir] != -1) break;
dep[pos[u].x][pos[u].y][pos[u].dir] = depth ++;
pos[u] = go(pos[u], u);
}
chain_len[u] = dep[pos[u].x][pos[u].y][pos[u].dir];
circle_len[u] = depth - dep[pos[u].x][pos[u].y][pos[u].dir];
memset(A[u], -1, sizeof A[u]);
for(int i = 1; i < circle_len[u]; i ++) {
if(pos[u].x == trap_x && pos[u].y == trap_y)
A[u][pos[u].dir] = dep[pos[u].x][pos[u].y][pos[u].dir] % circle_len[u];
pos[u] = go(pos[u], u);
}
}
void exgcd(__int128 a, __int128 b, __int128 &d, __int128 &x, __int128 &y) {
if(!b) {d = a, x = 1, y = 0; return; }
exgcd(b, a % b, d, y, x);
y -= (a / b) * x;
}
inline void solve(__int128 a1, __int128 m1, __int128 a2, __int128 m2, __int128 &a, __int128 &m) {
if(a2 < a1) swap(a1, a2), swap(m1, m2);
__int128 d, x, y;
exgcd(m1, m2, d, x, y);
if((a2 - a1) % d != 0) {
m = -1; return;
}
__int128 k = (a2 - a1) / d;
m = m1 / __gcd(m1, m2) * m2;
x = (x % m) * (k % m) % m;
a = ((a1 + (x % m) * (m1 % m) % m) % m + m) % m;
assert(a % m1 == a1 && a % m2 == a2);
}
__int128 ans = -1;
void dfs(int u, __int128 x, __int128 mod) {
if(u == k) {
for(int i = 0; i < k; i ++) {
if(x < chain_len[i])
x += (chain_len[i] - x + mod - 1) / mod * mod;
}
if(ans == -1) ans = x;
else ans = min(ans, x);
return;
}
for(int i = 0; i < 4; i ++) {
if(A[u][i] == -1) continue;
__int128 new_x, new_mod;
solve(x, mod, A[u][i], circle_len[u], new_x, new_mod);
if(new_mod != -1) dfs(u + 1, new_x, new_mod);
}
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
cin >> n >> m >> k;
cin >> trap_x >> trap_y;
for(int i = 0; i < k; i ++) {
int x, y, dir; char c; cin >> x >> y >> c; dir = get(c);
S[i].x = x, S[i].y = y, S[i].dir = dir;
pos[i] = S[i];
for(int j = 1; j <= n; j ++)
cin >> (G[i][j] + 1);
}
for(int i = 0; i <= 10000; i ++) {
if(check()) {
cout << i + 1 << '\n';
return 0;
}
for(int j = 0; j < k; j ++)
pos[j] = go(pos[j], j);
}
for(int u = 0; u < k; u ++)
pos[u] = S[u], calc(u);
for(int i = 0; i < 4; i ++)
if(A[0][i] != -1) dfs(1, A[0][i], circle_len[0]);
if(ans == -1) cout << "-1" << '\n';
else cout << ans + 1 << '\n';
return 0;
}
H. [CmdOI2019] 简单的数论题
题目描述
给出
输入格式
第一行一个整数
后
输出格式
对于每个询问,输出一行一个整数,表示答案。
样例 #1
样例输入 #1
5
10 10
20 20
30 30
40 40
50 50
样例输出 #1
768
13312
16218
7160
9031
样例 #2
样例输入 #2
3
5 4
20 15
100 88
样例输出 #2
52
7572
21475
提示
对于所有测试点,
测试点编号 | 时限 | 特殊性质 | ||
---|---|---|---|---|
#1~2 | ||||
#3~4 | ||||
#5~6 | ||||
#7~8 | ||||
#9~10 |
题解
要求再设
和阈值
此时答案可以表示为什么呢?不妨设
对于
#include <bits/stdc++.h>
using namespace std;
const int N = 5e4 + 10, MOD = 23333;
inline int Plus(int a, int b) {return a + b >= MOD ? a + b - MOD : a + b; }
inline int Minus(int a, int b) {return a - b < 0 ? a - b + MOD : a - b; }
int phi[N], mu[N], mind[N]; vector<int> primes;
vector<int> factor[N], G[N];
const int B = 200;
vector<int> H[B + 5][B + 5];
inline int calc(int x, int y, int z) {
int ans = 0;
for(auto d : factor[z])
ans = Plus(ans, G[x][d] * G[y][d] % MOD * mu[d] % MOD);
return ans;
}
inline void init(const int n = 50000) {
for(int i = 1; i <= n; i ++)
for(int j = i; j <= n; j += i)
factor[j].emplace_back(i);
phi[1] = 1, mu[1] = 1;
for(int i = 2; i <= n; i ++) {
if(!mind[i]) mind[i] = i, primes.emplace_back(i), phi[i] = (i - 1) % MOD, mu[i] = MOD - 1;
for(auto p : primes) {
if(1ll * p * i > n) break;
mind[p * i] = p;
if(i % p == 0) {
phi[p * i] = p * phi[i] % MOD, mu[p * i] = 0;
break;
} else phi[p * i] = phi[p] * phi[i] % MOD, mu[p * i] = Minus(0, mu[i]);
}
}
for(int i = 1; i <= n; i ++)
G[i].emplace_back(0);
for(int y = 1; y <= n; y ++) {
G[1].emplace_back(phi[y]);
for(int x = 2; x * y <= n; x ++)
G[x].emplace_back(Plus(G[x - 1][y], phi[x * y]));
}
for(int i = 1; i <= B; i ++) for(int j = 1; j <= B; j ++) {
H[i][j].emplace_back(0);
for(int k = 1; k * max(i, j) <= n; k ++)
H[i][j].emplace_back(Plus(H[i][j][k - 1], calc(i, j, k)));
}
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
init();
int T; cin >> T;
while(T --) {
int n, m; cin >> n >> m;
if(n > m) swap(n, m);
int ans = 0;
for(int i = 1; i <= m / B; i ++)
if(n / i && m / i) ans = Plus(ans, calc(n / i, m / i, i));
for(int l = m / B + 1, r; l <= n; l = r + 1) {
r = min(n / (n / l), m / (m / l));
ans = Plus(ans, Minus(H[n / l][m / l][r], H[n / l][m / l][l - 1]));
}
cout << ans << '\n';
}
return 0;
}
I.「2011 福建集训」最大团
题目描述
一张图是好图当且仅当它能被分成若干大小相等的团,记
给定
输入格式
第一行读入一个数
输出格式
输出包含
样例 #1
样例输入 #1
1
4 2
样例输出 #1
32
数据范围与提示
对于
题解
首先算对每个质因子算
#include <bits/stdc++.h>
using namespace std;
inline long long ksm(long long a, long long b, const int mod) {
long long r = 1;
for(; b; b >>= 1, a = a * a % mod)
if(b & 1) r = r * a % mod;
return r;
}
const int MOD = 1e9 - 401;
const int mod[] = {2, 13, 5281, 7283};
int n, m;
namespace solver {
map<pair<int, int>, pair<long long, long long>> Map;
long long calc1(int n, const int mod) {
if(!n) return 1;
long long ans = calc1(n / mod, mod);
long long val = 1;
if(n >= mod) {
for(int i = 1; i <= mod - 1; i ++)
val = val * i % mod;
val = ksm(val, n / mod, mod);
}
for(int i = mod * (n / mod) + 1; i <= n; i ++)
val = val * i % mod;
return ans * val % mod;
}
long long calc2(int n, const int mod) {
if(!n) return 0;
return calc2(n / mod, mod) + n / mod;
}
pair<long long, long long> main(int n, const int mod) {
if(Map.count({n, mod})) return Map[{n, mod}];
return Map[{n, mod}] = make_pair(calc1(n, mod), calc2(n, mod));
}
}
namespace crt {
void exgcd(long long a, long long b, long long &d, long long &x, long long &y) {
if(!b) {d = a, x = 1, y = 0; return; }
exgcd(b, a % b, d, y, x);
y -= (a / b) * x;
}
inline pair<long long, long long> merge(pair<long long, long long> A, pair<long long, long long> B) {
pair<long long, long long> C;
C.second = A.second * B.second;
if(A.first > B.first) swap(A, B);
long long d, x, y;
exgcd(A.second, B.second, d, x, y);
x = x * ((B.first - A.first) / d) % C.second;
if(x < 0) x += C.second;
C.first = (A.first + x * A.second) % C.second; if(C.first < 0) C.first += C.second;
return C;
}
}
inline int calc(int d) {
auto ans = make_pair(0, 1);
for(int i = 0; i < 4; i ++) {
pair<long long, long long> pr[3] = {solver::main(n, mod[i]), solver::main(d, mod[i]), solver::main(n / d, mod[i])};
pr[1].first = ksm(pr[1].first, n / d, mod[i]), pr[1].second = pr[1].second * (n / d);
long long c = pr[0].second - pr[1].second - pr[2].second;
long long val = pr[0].first;
val = val * ksm(pr[1].first, mod[i] - 2, mod[i]) % mod[i];
val = val * ksm(pr[2].first, mod[i] - 2, mod[i]) % mod[i];
val = val * ksm(mod[i], c, mod[i]) % mod[i];
ans = crt::merge(ans, make_pair(val, 1ll * mod[i]));
}
return ksm(m, ans.first, MOD);
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T; cin >> T;
while(T --) {
cin >> n >> m;
int ans = 1;
for(int d = 1; 1ll * d * d <= n; d ++) {
if(n % d) continue;
ans = 1ll * ans * calc(d) % MOD;
if(n / d != d) ans = 1ll * ans * calc(n / d) % MOD;
}
cout << ans << '\n';
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧