• bupt summer training for 16 #4 ——数论


    https://vjudge.net/contest/173277#overview

    A.平方差公式后变为 n = (x + y)(x - y)

    令 t = x - y ,变成

    n = (t + 2x) * t,要 x 最小

    O(sqrt(n)) 枚举 n 的因数即可

     1 #include <cstdio>
     2 
     3 typedef long long ll;
     4 
     5 ll n, m, k, t;
     6 
     7 int main() {
     8     scanf("%lld", &n);
     9     while(n --) {
    10         k = 0;
    11         scanf("%lld", &m);
    12         for(ll i = 1;i * i < m;i ++) {
    13             if((m % i == 0) && ((m / i - i) % 2 == 0) ) {
    14                 t = (m / i - i) / 2;
    15                 k = 1;
    16             }
    17         }
    18         if(!k) puts("-1");
    19         else printf("%lld
    ", t);
    20     }
    21     return 0;
    22 }
    View Code

    B.

    C.如果GCD中间是加号会困难很多

    乘号的话,我们枚举质数对ans的贡献即可

    质数 pi 对结果的贡献就是

    pow(pi,(n/pi)*(m/pi) + (n/pi^2)*(m/pi^2) + (n/pi^3)*(m/pi^3) +... )

    最坏效率,1kw质数大约 n / ln(n) 个

    pi = 2, 计算贡献需要logn次,快速幂约logn

    复杂度约为 O(n / ln(n) * logn),考虑到后面质数变大

    pi > 100时, 计算贡献就只有3次了

    实际计算贡献和快速幂平均下来不到2次

    所以 n = 1kw 时是O(n)级别的

     1 #include <cstdio>
     2 #include <algorithm>
     3 
     4 using std::swap;
     5 
     6 typedef long long ll;
     7 
     8 int p[10000010], v[10000010];
     9 
    10 int tt;
    11 
    12 long long n, m, ans;
    13 
    14 const int Mod = 1e9 + 7;
    15 
    16 ll calc(ll x, ll k) {
    17     ll res = 1;
    18     for(;k > 0;x = x * x % Mod, k >>= 1)
    19         if(k & 1) res = res * x % Mod;
    20     return res;
    21 }
    22 
    23 int main() {
    24     for(int i = 2;i <= 10000000;i ++) {
    25         if(!v[i]) p[++ p[0]] = i;
    26         for(int j = 1;j <= p[0] && 1ll * i * p[j] <= 10000000;j ++) {
    27             v[i * p[j]] = 1;
    28             if(i % p[j] == 0) break;
    29         }
    30     }
    31     long long t, cnt;
    32     scanf("%d", &tt);
    33     while(tt --) {
    34         ans = 1;
    35         scanf("%lld %lld", &n, &m);
    36         if(m > n) swap(n, m);
    37         for(int i = 1;p[i] <= m && i <= p[0];i ++) {
    38             t = p[i], cnt = 0;
    39             while(1) {
    40                 cnt += (n / t) * (m / t);
    41                 if(m / t >= p[i]) t *= p[i];
    42                 else break;
    43             }
    44             ans = ans * calc(p[i], cnt) % Mod;
    45         }
    46         printf("%lld
    ", ans);
    47     }
    48     return 0;
    49 }
    View Code

    D.这个题今年3月刚写的又忘记了...

    我们一个想法是分解质因数

    得到 n! 里每个质数出现的最少次数

    但我们平时分解质因数都是O(sqrt(n))的

    即使使用前缀和,10^7也无法O(n^1.5)分解

    所以这里用了一个巧妙又优秀的的O(nlogn)处理方法

     1 for(int i = 2;i * i <= m;i ++) {
     2         if(v[i]) continue;
     3         for(int j = i * i;j <= m;j += i)
     4             v[j] = -i;
     5     }
     6 for(int i = 2;i <= m;i ++) {
     7         int j = i;
     8         while(1) {
     9             if(v[j] >= 0) {
    10                 cout << j << endl;
    11                 break;
    12             }
    13             else cout << -v[j] << endl, j /= -v[j];
    14         }
    15     } 

    当 i 为非质数时, -vis[i] 存的是 i 的最大的不大于sqrt(i)的质因数

    分解质因数后可以二分

    也可以用每个质数出现的个数得到不等式 n >= ci

    实际效率约均为O(n)级别,前者思考复杂度低

     1 #include <bits/stdc++.h>
     2 
     3 #define rep(i, j, k) for(int i = j;i <= k;i ++)
     4 #define rev(i, j, k) for(int i = j;i >= k;i --)
     5 
     6 using namespace std;
     7 
     8 typedef long long ll;
     9 
    10 const int maxn = 10000010;
    11 
    12 int n, m, a[maxn], b[maxn], p[maxn];
    13 
    14 int v[maxn], num[maxn];
    15 
    16 ll cnt[maxn];
    17 
    18 bool judge(ll x) {
    19     ll y, c;
    20     rep(i, 1, p[0]) {
    21         y = x, c = 0;
    22         while(y) y /= p[i], c += y;
    23         if(c < cnt[i]) return 0;
    24     }
    25     return 1;
    26 }
    27 
    28 int main() {
    29     ios::sync_with_stdio(false);
    30     cin >> n;
    31     rep(i, 1, n) {
    32         cin >> a[i];
    33         m = max(m, a[i]);
    34         b[a[i]] ++;
    35     }
    36     for(int i = 2;i * i <= m;i ++) {
    37         if(v[i]) continue;
    38         for(int j = i * i;j <= m;j += i)
    39             v[j] = -i;
    40     }
    41     rep(i, 2, m)
    42         if(!v[i]) 
    43             p[++ p[0]] = i, num[i] = p[0];
    44     rev(i, m, 2)
    45         b[i] += b[i + 1];
    46     rep(i, 2, m) {
    47         int j = i;
    48         while(1) {
    49             if(v[j] >= 0) {
    50                 cnt[num[j]] += b[i];
    51                 break;
    52             }
    53             else cnt[num[-v[j]]] += b[i], j /= -v[j];
    54         }
    55     } 
    56     ll l = 1, r =  10000000000000ll, mid, ans;
    57     while(l <= r) {
    58         mid = (l + r) >> 1;
    59         if(judge(mid)) ans = mid, r = mid - 1;
    60         else l = mid + 1;
    61     }
    62     cout << ans;
    63     return 0;
    64 }
    View Code

    E.利用欧拉函数的性质,对于给定的 x

    满足 phi[n] >= x 的最小的 n 一定是个质数

    范围不大预处理即可

     1 #include <cstdio>
     2 
     3 const int maxn = 1000010;
     4 
     5 int pr[maxn], ph[maxn], vis[maxn];
     6 
     7 int Case, n, a, b[maxn];
     8 
     9 long long ans;
    10 
    11 int main() {
    12     for(int i = 2;i < maxn;i ++) {
    13         if(!vis[i]) {
    14             pr[++ pr[0]] = i;
    15             ph[i] = i - 1;
    16         }
    17         for(int j = 1;j <= pr[0] && i * pr[j] < maxn;j ++) {
    18             vis[i * pr[j]] = 1;
    19             if(i % pr[j] == 0) break;
    20         }
    21     }
    22     int last = 1000003;
    23     for(int i = 1000000;i;i --) {
    24         b[i] = last;
    25         if(ph[i]) last = i;
    26     }
    27     scanf("%d", &Case);
    28     for(int t = 1;t <= Case;t ++) {
    29         ans = 0;
    30         scanf("%d", &n);
    31         for(int j = 1;j <= n;j ++) {
    32             scanf("%d", &a);
    33             ans += b[a];
    34         }
    35         printf("Case %d: %lld Xukha
    ", t, ans);
    36     }
    37     return 0;
    38 }
    View Code

    F.

    G.求前几位的题目,取个对数就行

    利用斐波那契数列的通项公式

    我们发现后面减去的一项<1,n变大之后忽略即可

    取完对数乘法变加法

    最后输出前4位,必须舍去后面位数所以直接double转int

    %.0f 会四舍五入并不满足要求

     1 #include <cstdio>
     2 #include <cmath>
     3 #include <algorithm>
     4 
     5 using std::abs;
     6 
     7 int n, f[21];
     8 
     9 int main() {
    10     f[1] = 1;
    11     for(int i = 2;i < 21;i ++) f[i] = f[i - 1] + f[i - 2];
    12     while(scanf("%d", &n) != EOF) {
    13         if(n < 21) printf("%d
    ", f[n] % 10000);
    14         else {
    15             double x = (log(1 / sqrt(5.0)) + log((sqrt(5.0) + 1) / 2) * n) / log(10.0);
    16             x -= (int)x;
    17             x = pow(10, x);
    18             while(x < 1000) x *= 10;
    19             printf("%d
    ", (int)x);
    20         }
    21     }
    22     return 0;
    23 }
    View Code

    H.

    I.混进来的放水题目

    可以先把每一层节点都挂到上一层的一个节点上

    可以出现最多的叶子节点

    如果发现太多了就开始把当前层的节点

    往上一层的其他节点上挪动,每动一次减少一个叶子节点

     1 #include <cstdio>
     2 
     3 const int maxn = 200010;
     4 
     5 int n, t, k, b[maxn], s[maxn], a[maxn];
     6 
     7 int main() {
     8     s[1] = 2, s[0] = 1;
     9     scanf("%d %d %d", &n, &t, &k);
    10     if(k > n - t) {
    11         puts("-1");
    12         return 0;
    13     }
    14     for(int j = 2,i = 1;i <= t;i ++) {
    15         scanf("%d", &a[i]), s[i + 1] = a[i] + s[i];
    16         for(int p = 1;p <= a[i];p ++, j ++)
    17             b[j] = s[i - 1];
    18     }
    19     k = n - t - k;
    20     if(k > 0) {
    21         for(int p = 2;p <= t;p ++) {
    22             for(int j = s[p - 1] + 1, i = s[p] + 1;i < s[p + 1] && j < s[p];i ++, j ++) {
    23                 b[i] = j, k --;
    24                 if(!k) break;
    25             }
    26             if(!k) break;
    27         }
    28     }
    29     if(k) puts("-1");
    30     else {
    31         printf("%d
    ", n);
    32         for(int i = 2;i <= n;i ++)
    33             printf("%d %d
    ", i, b[i]);
    34     }
    35 }
    View Code

    J.快速幂水题

    另外因为2009非质数,所以不到50的时候ans已经变成0了

     1 #include <cstdio>
     2 
     3 typedef long long ll;
     4 
     5 ll n, a[3000];
     6 
     7 ll power(ll x, ll k) {
     8     ll res = 1;
     9     for(;k;k >>= 1, x = x * x % 2009)
    10         if(k & 1) res = res * x % 2009;
    11     return res;
    12 }
    13 
    14 int main() {
    15     ll m, ans;
    16     a[0] = 1, a[1] = 1;
    17     for(int i = 2;i < 2009;i ++)
    18         a[i] = a[i - 1] * i % 2009;
    19     while(scanf("%lld", &n) != EOF) {
    20         ans = 1;
    21         m = n / 2009;
    22         ans *= power(a[2008], m);
    23         printf("%lld
    ", ans * a[n % 2009] % 2009);
    24     }
    25     return 0;
    26 }
    View Code
  • 相关阅读:
    java内部类
    unityUI拖拽
    Java泛型
    java集合
    python爬取糗百段子
    python读取文件并保存到mysql数据库
    BeanShell Sampler 身份证号-jmeter
    python操作数据库
    创建身份证号
    随机生成四要素
  • 原文地址:https://www.cnblogs.com/ytytzzz/p/7253517.html
Copyright © 2020-2023  润新知