小国的复仇 想法题/数学题附数论模板
题意:
链接:https://www.nowcoder.com/acm/contest/107/G
来源:牛客网
初始的时候小国和小杰各有1个。经过了很久的修炼,汀老师学会了两种魔法,他每次可以动用自己的智慧来使用魔法。
第一个魔法:(小杰变小国)可以将自己的智慧复制和当前小杰一样数量的小国出来;
第二个魔法:(小国大爆发)可以将当前的小杰变成和小国的数量一样,然后小国的数量加倍!
题解:将两个参数化为一维,于是有一个递推方程a[j + i] = min(a[j + i], a[i] + j / i);
疑问:1e6的循环能过?
ac核心代码。
memset(a, 0x3f, sizeof(a)); a[1] = 0; for (int i = 1; i <= 1000000; ++i) for (int j = i; j + i <= 1000000; j += i) a[j + i] = min(a[j + i], a[i] + j / i);
附:数论模板orz
#include <iostream> #include <vector> #include <cstdlib> #include <algorithm> #include <cstring> #include <cmath> using namespace std; class NumberTheory { public: // 预打标后的数的最小因子 std::vector<unsigned int> MinFactor; // 预打表中搜索到的素数集 std::vector<unsigned int> Prime; // 预打表欧拉函数 std::vector<unsigned int> Phi; // 预打表最大数 unsigned int MaxNumber; // 用于递归传递参数 没有实质作用 std::vector<long long int> temp; // 不打表构造函数 NumberTheory() { MaxNumber = 0; } // 预打表到MaxNumber构造函数 explicit NumberTheory(unsigned int MaxNumber) { this->MaxNumber = MaxNumber; MaxNumber = std::max(MaxNumber + 1, (unsigned int) 2); Phi.resize(MaxNumber); MinFactor.resize(MaxNumber); MinFactor[1] = 1; Phi[1] = 1; for (unsigned int i = 2; i < MaxNumber; i++) { if (Phi[i] == 0) { Prime.push_back(i); Phi[i] = i - 1; MinFactor[i] = i; } for (unsigned int j = 0; j < Prime.size() && Prime[j] * i < MaxNumber; j++) { if (i % Prime[j] == 0) { MinFactor[i * Prime[j]] = Prime[j]; Phi[i * Prime[j]] = Phi[i] * Prime[j]; break; } MinFactor[i * Prime[j]] = Prime[j]; Phi[i * Prime[j]] = Phi[i] * (Prime[j] - 1); } } } long long int abs(int x) { return x > 0 ? x : -x; } // 快速幂 long long fastpower(long long a, long long n) { long long res = 1; while (n > 0) { if (n & 1)res = res * a; a = a * a; n >>= 1; } return res; } // 判断是否是素数 bool IsPrime(long long int n) { if (n <= MaxNumber) // 在表中O(1)查表 return MinFactor[n] == n; // 不在表中用Miller_Rabin return Miller_Rabin(n); } // 最大公约数 long long int gcd(long long int a, long long int b) { return b ? gcd(b, a % b) : a; } // 多个数最大公约数 long long int gcd(std::vector<int> v) { if (v.size() < 2) return -1; long long int res = v[0]; for (int i = 1; i < v.size(); i++) { res = gcd(res, v[i]); } return res; } // 最小公倍数 long long int lcm(long long int a, long long int b) { return a * b / gcd(a, b); } // 带模快速乘法 long long int modular_multi(long long int x, long long int y, long long int mo) { long long int t; x %= mo; for (t = 0; y; x = (x << 1) % mo, y >>= 1) if (y & 1) t = (t + x) % mo; return t; } /*long long int modular_exp(char *N, long long int t, long long int mo) { //unsure!!! return modular_exp(t,PhiMa(N,mo),mo); }*/ // 带模快速幂 long long int modular_exp(long long int num, long long int t, long long int mo) { long long int ret = 1, temp = num % mo; for (; t; t >>= 1, temp = modular_multi(temp, temp, mo)) if (t & 1) ret = modular_multi(ret, temp, mo); return ret; } // 费马小定理整理指数 long long int PhiMa(char *N, int mod) { long long ans = 0; for (int i = 0; N[i] != '\0'; i++) ans = (ans * 10 + N[i] - '0') % mod; return ans; } // Miller_Rabin判断素数 bool Miller_Rabin(long long int n) { return Miller_Rabin(n, 40); } // Miller_Rabin判断素数 bool Miller_Rabin(long long int n, long long int S) { if (n == 2)return true; if (n < 2 || !(n & 1))return false; int t = 0; long long int a, x, y, u = n - 1; while ((u & 1) == 0) t++, u >>= 1; for (int i = 0; i < S; i++) { a = rand() % (n - 1) + 1; x = modular_exp(a, u, n); for (int j = 0; j < t; j++) { y = modular_multi(x, x, n); if (y == 1 && x != 1 && x != n - 1) return false; x = y; } if (x != 1) return false; } return true; } // 扩展欧几里得 long long int extern_gcd(long long int a, long long int b, long long int &x, long long int &y) { if (b == 0) { x = 1; y = 0; return a; } long long int ans; long long int x1, y1; ans = extern_gcd(b, a % b, x1, y1); if (a * b < 0) { x = -y1; y = a / b * y1 - x1; } else { x = y1; y = x1 - a / b * y1; } return ans; } // // 带c扩展欧几里得 // int extern_gcd(long long int a, long long int b, long long int c, long long int &x, long long int &y) { // long long int result = extern_gcd(a, b, x, y); // x *= c / gcd(a, b); // y *= c / gcd(a, b); // // } // 模逆元 long long int Inverse(long long int a, long long int m) { long long int x, y; long long int gcd = extern_gcd(a, m, x, y); if (1 % gcd != 0) return -1; x *= 1 / gcd; m = abs(m); long long int ans = x % m; if (ans <= 0)ans += m; return ans; } // Pollard_Rho分解因数 long long Pollard_Rho(long long n, int c) { long long i = 1, k = 2, x = rand() % (n - 1) + 1, y = x; while (true) { i++; x = (modular_multi(x, x, n) + c) % n; long long p = gcd((y - x + n) % n, n); if (p != 1 && p != n) return p; if (y == x) return n; if (i == k) { y = x; k <<= 1; } } } // 分解质因数 返回值是vector std::vector<long long int> DecomposingFactor(long long int n) { temp.resize(0); if (n <= MaxNumber) { while (n != 1) { temp.push_back((long long int) MinFactor[n]); n /= MinFactor[n]; } } else find(n, 103); std::sort(temp.begin(), temp.end()); return temp; } // 寻找因数 void find(long long n, int c) { if (n == 1) return; if (Miller_Rabin(n)) { temp.push_back(n); return; } long long p = n, k = c; while (p >= n) p = Pollard_Rho(p, c--); find(p, k); find(n / p, k); } // 中国剩余定理(参数是向量) long long int CRT(std::vector<long long int> a, std::vector<long long int> m) { if (a.size() != m.size() || a.empty())return -1; int k = a.size(); long long int N[k];//这个可以删除 long long int mm = 1;//最小公倍数 long long int result = 0; for (int i = 0; i < k; i++) { mm *= m[i]; } for (int j = 0; j < k; j++) { long long int L, J; extern_gcd(mm / m[j], -m[j], L, J); //N[j] = m[j] * J + 1;//1 N[j] = mm / m[j] * L;//2 1和2这两个值应该是相等的。(可优化) result += N[j] * a[j]; } return (result % mm + mm) % mm;//落在(0, mm)之间,这么写是为了防止result初始为负数 } // 不打表硬算欧拉函数 long long int Euler(long long int n) { long long int m = floor(sqrt(n + 0.5)); long long int ans = n; for (int i = 2; i <= m; i++) { if (n % i == 0) { ans = ans / i * (i - 1); while (n % i == 0) n /= i; } } if (n > 1) ans = ans / n * (n - 1); return ans; } // 带模快速幂(欧拉函数优化,字符串指数) long long int modular_exp(long long int a, char str[], long long int mod) { long long int len = strlen(str); long long int res = 0; long long int t = Euler(mod); if (len <= 15) { for (int i = 0; i < len; i++) { res = res * 10 + str[i] - '0'; } } else { for (int i = 0; i < len; i++) { res = res * 10 + str[i] - '0'; res %= t; } if (res < 0) res += t; // Or "+mod"? I'am confused. } return modular_exp(a, res, mod); } }; int main(){ NumberTheory number(1000005); int t; scanf("%d",&t); while(t--){ int n;scanf("%d",&n); if(number.IsPrime(n)){ cout<<n-1<<endl; continue; } vector<long long int> q = number.DecomposingFactor(n); long long int sum = 0; for(int i=0;i<q.size();i++){ sum+=q[i]-1; } printf("%lld\n",sum); } return 0; }
成功的路并不拥挤,因为大部分人都在颓(笑)