21/29
题目都很基础,有很多题书上讲得比较详细,然后隔得时间有点久,所以具体什么trick都忘了,思路也懒得去回忆,所以将就着放上来了。。。。
例题10–1 Uva 11582
题意:输入a, b, n让你计算F[a^b]%n;其中这个F[i]是斐波那契数;
题解:
这题是快速幂+找循环节,用什么方法找循环节呢?因为第一个数是0和1,然后当再出现0和1的时候就是出现循环节的时候,然后假如找到了循环节T,然后就有F[n] = F[n % T],预处理找循环节,O(一百万左右),快速幂logn * 10000组数据,复杂度并不高;最后一个注意:给佳哥坑了,f(0)= 0, f(1) = 1;书上写错了。
1 /*zhen hao*/
2 #include <bits/stdc++.h>
3 using namespace std;
4
5 typedef unsigned long long ull;
6 const int maxn = 1001;
7 int F[maxn][maxn * 6], len[maxn];
8
9 void pre_slove() {
10 for (int n = 2; n <= 1000; n++) {
11 F[n][0] = 0; F[n][1] = 1;
12 for (int i = 2; ; i++) {
13 F[n][i] = (F[n][i - 1] + F[n][i - 2]) % n;
14 if (F[n][i - 1] == 0 && F[n][i] == 1) {
15 len[n] = i - 1; break;
16 }
17 }
18 }
19 }
20
21 int quick(ull a, ull b, ull mod) {
22 int ret = 1;
23 a %= mod;
24 while (b) {
25 if (b & 1) ret = ret * a % mod;
26 b = b / 2;
27 a = a * a % mod;
28 }
29 return ret;
30 }
31
32 int main() {
33 //freopen("case.in", "r", stdin);
34 pre_slove();
35 int T;
36 scanf("%d", &T);
37 while (T--) {
38 ull a, b;
39 int n;
40 cin >> a >> b >> n;
41 if (n == 1) { puts("0"); continue; }
42 printf("%d
", F[n][quick(a, b, ull(len[n]))]);
43 }
44 return 0;
45 }
例题10-2 uva12169
题意:给你n个数,这n个数是x1,x3,……,x2*n-1,是由递推式子xi = (xi-1 * a + b) % 10001得到的,现在让你输出一组可能的x2……x2n;
题解:先要确定的是a和b都可以是0~10001,有模运算可知,然后就是枚举a,然后根据式子:
x2 = (x1 * a + b) % n;
x3 = (x2 * a + b) % n;
化简可得:
b * (a + 1) - k * n = x3 - x1 * a ^ 2;
这个类似ax + by = c的形式,可以用扩展欧几里得算法求出b和k,b的范围可以化简到0~n-1,然后判定是不是可行解,然后输出即可。
1 /*zhen hao*/
2 #include <bits/stdc++.h>
3 using namespace std;
4
5 typedef long long ll;
6 const int maxn = 1e4 + 100;
7 const int mod = 1e4 + 1;
8 int v[maxn];
9
10 void gcd(ll a, ll b, ll& d, ll& x, ll& y) {
11 if (!b) { d = a; x = 1; y = 0; }
12 else {
13 gcd(b, a % b, d, y, x); y -= x * (a / b);
14 }
15 }
16
17 int main() {
18 //freopen("case.in", "r", stdin);
19 int n;
20 while (scanf("%d", &n) == 1) {
21 for (int i = 0, j = 1; i < n; i++, j += 2) scanf("%d", v+ j);
22 bool f = true;
23 ll x, y, d, a, b, c;
24 for (a = 0; a < mod && f; a++) {
25 gcd(a + 1, mod, d, x, y);
26 c = v[3] - a * a * v[1];
27 if (c % d) continue;
28 b = (x * c / d + mod * 10) % mod;
29 f = false;
30 for (int i = 3; i <= 2 * n - 1 && !f; i += 2) {
31 v[i - 1] = (v[i - 2] * a + b) % mod;
32 if (v[i] != (v[i - 1] * a + b) % mod) f = true;
33 }
34 if (!f) v[2 * n] = (v[2 * n - 1] * a + b) % mod;
35 }
36 for (int i = 2; i <= 2 * n; i += 2) printf("%d
", v[i]);
37 }
38 return 0;
39 }
例题10-3 uva10375
题意:略
题解:唯一分解定理。
1 /*zhen hao*/
2 #include <bits/stdc++.h>
3 using namespace std;
4
5 const int maxn = 1e4 + 100;
6 bool vis[maxn];
7 vector<int> primes;
8 int cnt[maxn];
9
10 void pre_slove(int n) {
11 int m = sqrt(n + 0.5);
12 for (int i = 2; i <= m; i++) if (!vis[i])
13 for (int j = i * i; j < maxn; j += i) vis[j] = true;
14
15 for (int i = 2; i < maxn; i++) if (!vis[i])
16 primes.push_back(i);
17 }
18
19 void get_cnt(int n, int d) {
20 for (int i = 0; i < (int)primes.size() && primes[i] <= n; i++) {
21 while (n % primes[i] == 0) {
22 cnt[i] += d;
23 n /= primes[i];
24 }
25 }
26 }
27
28 int main() {
29 //freopen("case.in","r", stdin);
30 pre_slove(maxn);
31 int p, q, r, s;
32 while (cin >> p >> q >> r >> s) {
33 memset(cnt, 0, sizeof cnt);
34 for (int i = 0; i < q; i++) {
35 get_cnt(p - i, 1);
36 get_cnt(i + 1, -1);
37 }
38 for (int i = 0; i < s; i++) {
39 get_cnt(r - i, -1);
40 get_cnt(i + 1, 1);
41 }
42 double ans = 1.0;
43 for (int i = 0; i < maxn; i++) if (cnt[i]) {
44 ans *= powl(primes[i] * 1.0, cnt[i] * 1.0);
45 }
46 printf("%.5lf
", ans);
47
48 }
49 return 0;
50 }
例题10-4 uva 10791
题意:找几个数的公倍数为n的最小的和。
题解:唯一分解定理的各个项相加即是答案。
1 /*zhen hao*/
2 #include <bits/stdc++.h>
3 using namespace std;
4
5 typedef long long ll;
6 const int maxn = 1 << 16;
7 bool vis[maxn];
8 vector<int> primes;
9
10 void pre_slove(int n) {
11 int m = sqrt(n + 0.5);
12 for (int i = 2; i <= m; i++) if (!vis[i])
13 for (int j = i * i; j < n; j += i) vis[j] = true;
14
15 for (int i = 2; i < n; i++) if (!vis[i])
16 primes.push_back(i);
17 }
18
19 ll get_ans(ll n) {
20 if (n == 1) return 2;
21 ll ret = 0;
22 int cnt = 0;
23 for (int i = 0; i < (int)primes.size() && n >= primes[i]; i++)
24 if (n % primes[i] == 0) {
25 ll x = 1;
26 while (n % primes[i] == 0) {
27 x *= primes[i]; n /= primes[i];
28 }
29 cnt++; ret += x;
30 }
31 if (n > 1) { ret += n; cnt++; }
32 if (cnt == 1) ret++;
33 return ret;
34 }
35
36 int main() {
37 //freopen("case.in", "r", stdin);
38 pre_slove(maxn);
39 ll n;
40 int tcase = 0;
41 while (cin >> n, n) {
42 cout << "Case " << ++tcase << ": " << get_ans(n) << endl;
43 }
44 return 0;
45 }
例题10-5 uva12716
题意:略
题解:具体思路跟紫书说的一样:先枚举约数c和其中一个较大的数a,然后得到b,然后判定是否存在gcd(a, a ^ c) = c;这样的复杂度是O(nlognlogn);
枚举a和c的代码如下:
for (int c = 1; c < maxn; c++)
for (int a = c + c; a < maxn; a += c)
就像素数筛法一样,对于c,2c,3c……都存在c这个约数。
最后发现有一个性质:满足a - c = b;所以就省去了一个log;
结合书和博客证明一下这个结论:
(1)首先前提是a - b <= a ^ b;
(2)设a - b = c;那么有a - b <= c;
(3)因为gcd(a, b) = c; 那么a = ca’, b = cb’,然后a - b = c(a’ - b’) >= c; 即c <= a - b <= c;
1 /*zhen hao*/
2 #include <bits/stdc++.h>
3 using namespace std;
4
5 const int maxn = 3e7 + 1;
6 int cnt[maxn], sum[maxn];
7
8 void pre_slove() {
9 for (int c = 1; c < maxn; c++)
10 for (int a = c + c; a < maxn; a += c) {
11 if (a - c == (a ^ c)) cnt[a]++;
12 }
13 for (int i = 1; i < maxn; i++) sum[i] = sum[i - 1] + cnt[i];
14 }
15
16 int main() {
17 //freopen("case.in", "r", stdin);
18 pre_slove();
19 int T, tcase = 0;
20 scanf("%d", &T);
21 while (T--) {
22 int n;
23 scanf("%d", &n);
24 printf("Case %d: %d
", ++tcase, sum[n]);
25 }
26 return 0;
27 }
例题10-6 uva10820
题意:略
题解:书上很详细,就是找组合数C(0,n-1), C(1,n-1), ……,C(n-1,n-1)中有多少个能被m整除,方法是把m分解,找当前有没有全部覆盖它的所有因子即可。
1 /*zhen hao*/
2 #include <bits/stdc++.h>
3 #define fi first
4 #define se second
5 using namespace std;
6
7 typedef pair<int,int> pii;
8 const int maxn = 1e5 + 10;
9 int mp1[maxn], mp2[maxn], cnt;
10 bool vis[maxn];
11 vector<int> primes, ans;
12 vector<pii> PII[maxn];
13
14 void pre_slove() {
15 int m = sqrt(maxn + 0.5);
16 for (int i = 2; i <= m; i++) if (!vis[i])
17 for (int j = i * i; j < maxn; j += i) vis[j] = 1;
18 for (int i = 2; i < maxn; i++) if (!vis[i])
19 primes.push_back(i);
20
21 for (int i = 2; i < maxn; i++) {
22 int x = i;
23 for (int j = 0; j < (int)primes.size() && x >= primes[j]; j++) if (x % primes[j] == 0) {
24 int t = 0;
25 while (x % primes[j] == 0) {
26 x /= primes[j];
27 t++;
28 }
29 PII[i].push_back(make_pair(primes[j], t));
30 }
31 }
32 }
33
34 void init() {
35 memset(mp1, 0, sizeof mp1);
36 memset(mp2, 0, sizeof mp2);
37 cnt = 0;
38 ans.clear();
39 }
40
41 bool divide(int m, int n) {
42 if (m == 1) {
43 for (int i = 1; i <= n; i++) ans.push_back(i);
44 return false;
45 }
46
47 for (int i = 0; i < (int)primes.size() && m >= primes[i]; ++i) if (m % primes[i] == 0) {
48 ++cnt;
49 while (m % primes[i] == 0) {
50 m /= primes[i];
51 mp2[primes[i]]++;
52 }
53 }
54 if (m > 1) return false;
55 return true;
56 }
57
58 void slove(int n) {
59 int now = 0, x;
60 for (int i = 1; i <= n; i++) {
61 x = n - i + 1;
62 for (int j = 0; j < (int)PII[x].size(); j++) {
63 pii& p = PII[x][j];
64 if (mp2[p.fi] && mp1[p.fi] < mp2[p.fi] && mp1[p.fi] + p.se >= mp2[p.fi]) now++;
65 mp1[p.fi] += p.se;
66 }
67 x = i;
68 for (int j = 0; j < (int)PII[x].size(); j++) {
69 pii& p = PII[x][j];
70 if (mp2[p.fi] && mp1[p.fi] >= mp2[p.fi] && mp1[p.fi] - p.se < mp2[p.fi]) now--;
71 mp1[p.fi] -= p.se;
72 }
73 if (now == cnt) ans.push_back(i + 1);
74 }
75 }
76
77 int main() {
78 //freopen("case.in", "r", stdin);
79 pre_slove();
80 int n, m;
81 while (scanf("%d%d", &n, &m) == 2) {
82 init();
83
84 if (divide(m, n)) slove(n - 1);
85
86 printf("%d
", (int)ans.size());
87 if (!ans.empty()) {
88 printf("%d", ans[0]);
89 for (int i = 1; i < (int)ans.size(); i++) printf(" %d", ans[i]);
90 }
91 printf("
");
92 }
93 return 0;
94 }
例题10-7 uva10820
题意:计算1 <= x,y <= n有多少个满足gcd(x,y) = 1?
题解:略
1 /*zhen hao*/
2 #include <bits/stdc++.h>
3 using namespace std;
4
5 typedef long long ll;
6 const int maxn = 5e4 + 100;
7 int phi[maxn];
8
9 void phi_table(int n) {
10 for (int i = 2; i <= n; i++) phi[i] = 0;
11 phi[1] = 1;
12 for (int i = 2; i <= n; i++) if (!phi[i])
13 for (int j = i; j <= n; j += i) {
14 if (!phi[j]) phi[j] = j;
15 phi[j] = phi[j] / i * (i - 1);
16 }
17 for (int i = 3; i <= n; i++) phi[i] += phi[i - 1];
18 }
19
20 int main() {
21 //freopen("case.in", "r", stdin);
22 phi_table(maxn - 1);
23 int n;
24 while (scanf("%d", &n) && n) {
25 ll ans = phi[n] * 2 + 1;
26 if (n == 1) ans = 1;
27 printf("%d
", ans);
28 }
29 return 0;
30 }
例题 10-8
题意:找这两个表中每一列都一样的字符,然后顺序取每一列,然后找字典序第k小。
题解:两种方法:
1、直接暴力dfs枚举
2、递推来找(像拆排列一样)
1 /*zhen hao*/
2 #include <bits/stdc++.h>
3 using namespace std;
4
5 const int maxn = 90;
6 int k, now;
7 char s[maxn];
8 char M1[maxn][maxn], M2[maxn][maxn];
9
10 bool dfs(int cur) {
11 if (cur == 5) {
12 if (++now == k) {
13 s[cur] = '