第一道:
求N^N次最后一个数字
快速幂mod10咯
代码如下:
#include#define ll long longusing namespace std;const int mod = 10;int qm(ll a,ll b) { ll res = 1; while (b) { if (b & 1) res = res * a % mod; a = a * a % mod; b >>= 1; } return (int)res;}int main() { int T; scanf("%d", &T); while (T--) { int n; scanf("%d", &n); printf("%d\n", qm((ll)n, (ll)n)); } return 0;}
好像可以打表找规律。
第二道:
从2*b开始枚举c就可以啦
代码如下:
#includeusing namespace std;int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b);}int main() { int n; scanf("%d", &n); while (n--) { int a, b; scanf("%d%d", &a, &b); for (int i = 2; ; i++) { int c = i * b; if (gcd(a, c) == b) { printf("%d\n", c); break; } } } return 0;}
第三道:
求 (A / B) % 9973
就是求A * INV(B) % 9973咯
由费马小定理 a^(p-1) ≡ 1(mod p)
所以 a * a^(p-2) ≡ 1(mod p)
所以INV(B) = b ^ (MOD-2)
代码如下:
#include#define ll long longusing namespace std;const int mod = 9973;int qm(ll a,ll b) { ll res = 1; while (b) { if (b & 1) res = res * a % mod; a = a * a % mod; b >>= 1; } return (int)res;}int main() { int T; scanf("%d", &T); while (T--) { int a, b; scanf("%d%d", &a, &b); printf("%d\n", a * qm((ll)b, (ll)mod - 2) % mod); } return 0;}
第四道:
最基本的矩阵快速幂(今天才学(可见刷题数量之少,以及之菜
和普通快速幂一个道理,就是加上矩阵相乘,以及定义ans变量的时候要定义成单位矩阵的形式
#includeusing namespace std;const int mod = 10000;struct Matrix { int m[2][2];} ans, base;Matrix mul(Matrix a, Matrix b) { Matrix temp; for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { temp.m[i][j] = 0; for (int k = 0; k < 2; k++) { temp.m[i][j] = (temp.m[i][j] + a.m[i][k] * b.m[k][j]) % mod; } } } return temp;}int qm(int n) { base.m[0][0] = base.m[0][1] = base.m[1][0] = 1; base.m[1][1] = 0; ans.m[0][0] = ans.m[1][1] = 1; ans.m[0][1] = ans.m[1][0] = 0; while (n) { if (n & 1) ans = mul(ans, base); base = mul(base, base); n >>= 1; } return ans.m[0][1];}int main() { int n; while (~scanf("%d", &n) && n != -1) { printf("%d\n", qm(n)); } return 0;}
第五道:
扩展欧几里得算法
分为x % k == 0 和 不等于 0 两种情况
如果x % k == 0 直接找一个p + q = k的解打印就好了
如果不整除
令 a = [x / k] 即求 x = a * p + (a + 1) * q 一组整数解
又因为GCD(a, a + 1) = 1 所以就可以先用扩展欧几里得算法求a * p + (a + 1) * q = 1
p q再分别乘以x就好了
#include#define ll long longusing namespace std;void extgcd(ll a, ll b, ll& d, ll& x, ll& y) { if (b) { extgcd(b, a % b, d, y, x); y -= (a / b) * x; } else { d = a; x = 1, y = 0; }}int main() { int T; scanf("%d", &T); while (T--) { ll x, k; scanf("%lld%lld", &x, &k); if (x % k == 0) { printf("%d %lld\n", 0, k); continue; } ll p, q; ll a = x / k; ll d; extgcd(a, a + 1, d, p, q); p *= x / d, q *= x / d; printf("%lld %lld\n", p, q); } return 0;}
第六道:
给定一个数n,求先增后减或先减后增或单调增或单调减的排列个数
先看 1,2,...,n
考虑把这个序列变成先增后减的情况 那么就有一个地方得容纳n
从左边n-1个数取0个放到n的右边 C(n-1, 0)
取1个 C(n-1, 1)
取两个 C(n-1, 2) 这两个元素取出来后放到n的右边只有一种排列方式, 就是从大到小排 因为要先增后减 到了n已经停止增 所以只能减
取3个 C(n-1, 3)
......
取n-1个 C(n-1, n-1)
那么可能数就为 C(n-1,0) + C(n-1,1) + ... + C(n-1, n-1) = (1 + 1) ^ (n - 1) = 2 ^ (n - 1)
那么对印的先减后增也是 2 ^ (n - 1)
但是会重复算单调增和单调减的序列
所以答案就是 2^n - 2
n, p <= 1e18
在快速幂的过程中很有可能会溢出long long
所以加上快速乘法(用加法模拟乘法,每一次都取模,这样保证不会溢出)
特判一下1的情况
代码如下:
#include#define ll long longusing namespace std;ll quick_mul(ll a, ll b, ll mod) { ll ans = 0; while (b) { if (b & 1) ans = (ans + a) % mod; a = (a + a) % mod; b >>= 1; } return ans;}ll quick_mod(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1) { ans = quick_mul(ans, a, mod) % mod; } a = quick_mul(a, a, mod) % mod; b >>= 1; } return ans;}int main() { ll n, q; while (~scanf("%lld%lld", &n, &q)) { if (n == 1) printf("%lld\n", 1 % q); else printf("%lld\n", (quick_mod(2, n, q) - 2 + q) % q); } return 0;}