• 2018中国大学生程序设计竞赛


    A - Buy and Resell

    题意:给出n个交易点,每次能够选择买或者卖,求获得最大利润

    思路:维护两个优先队列,一个是卖,一个是替换,当价格差相同时,优先替换,因为次数要最少

     1 #include <bits/stdc++.h>
     2 using namespace std; 
     3 
     4 #define ll long long
     5 #define N 100010
     6 
     7 int t, n;
     8 ll arr[N]; 
     9 priority_queue <ll, vector <ll>, greater <ll> > q[2];
    10 
    11 inline void Run()
    12 {
    13     scanf("%d", &t);
    14     while (t--)
    15     {
    16         scanf("%d", &n);
    17         for (int i = 1; i <= n; ++i) scanf("%lld", arr + i);
    18         for (int i = 0; i < 2; ++i) while (!q[i].empty()) q[i].pop();
    19         ll ans = 0;
    20         for (int i = 1; i <= n; ++i)
    21         {
    22             if (q[0].empty() && q[1].empty()) q[0].emplace(arr[i]);
    23             else if (q[1].empty())
    24             {
    25                 ll top = q[0].top();
    26                 if (arr[i] > top)
    27                 {
    28                     q[0].pop();
    29                     ans += arr[i] - top;
    30                     q[1].emplace(arr[i]);
    31                 }
    32                 else
    33                     q[0].emplace(arr[i]);
    34             }
    35             else if (q[0].empty())
    36             {
    37                 ll top = q[1].top();
    38                 if (arr[i] > top)
    39                 {
    40                     q[1].pop();
    41                     ans += arr[i] - top;
    42                     q[0].emplace(top); 
    43                     q[1].emplace(arr[i]);
    44                 }
    45                 else
    46                 {
    47                     q[0].emplace(arr[i]);
    48                 }
    49             }
    50             else
    51             {
    52                 ll top1 = q[0].top(), top2 = q[1].top();
    53                 if (top1 < top2)
    54                 {
    55                     if (arr[i] > top1)
    56                     {
    57                         q[0].pop();
    58                         ans += arr[i] - top1;
    59                         q[1].emplace(arr[i]);
    60                     }
    61                     else
    62                     {
    63                         q[0].emplace(arr[i]);
    64                     }
    65                 }
    66                 else
    67                 {
    68                     if (arr[i] > top2)
    69                     {
    70                         q[1].pop();
    71                         ans += arr[i] - top2;
    72                         q[0].emplace(top2);
    73                         q[1].emplace(arr[i]);
    74                     }
    75                     else
    76                     {
    77                         q[0].emplace(arr[i]); 
    78                     }
    79                 }
    80             }
    81         }
    82         printf("%lld %d
    ", ans, q[1].size() * 2);
    83     }
    84 }
    85 
    86 int main()
    87 {
    88     #ifdef LOCAL
    89         freopen("Test.in", "r", stdin); 
    90     #endif
    91 
    92     Run();
    93     
    94     return 0;
    95 }
    View Code

    B - Congruence equation

    留坑。

    C - Dream

    题意:给出一个p,重定义加法和乘法,使得$(m + n)^p = m^p + n^p $

    思路:有费马小定理  $a^p equiv a pmod p$

    那只需要重定义

              $(m + n) = (m + n) pmod p$

              $(m cdot n) = (m cdot n) pmod p$

    原根可以保证两个集合相等

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 #define N 2010
     6 
     7 int t, p;
     8 int a[N][N], b[N][N];
     9 
    10 inline void Run()
    11 {
    12     scanf("%d", &t);
    13     while (t--)
    14     {
    15         scanf("%d", &p);
    16         for (int i = 0; i < p; ++i)
    17         {
    18             for (int j = 0; j < p; ++j)
    19             {
    20                 a[i][j] = (i + j) % p;
    21                 b[i][j] = (i * j) % p;
    22             }
    23         }
    24         for (int i = 0; i < p; ++i)
    25         {
    26             for (int j = 0; j < p; ++j)
    27             {
    28                 printf("%d%c", a[i][j], " 
    "[j == p - 1]);
    29             }
    30         }
    31         for (int i = 0; i < p; ++i)
    32         {
    33             for (int j = 0; j < p; ++j)
    34             {
    35                 printf("%d%c", b[i][j], " 
    "[j == p - 1]);
    36             }
    37         }
    38     }
    39 }
    40 
    41 int main()
    42 {
    43     #ifdef LOCAL
    44         freopen("Test.in", "r", stdin);
    45     #endif
    46 
    47     Run();
    48 
    49     return 0;
    50 }
    View Code

    D - Find Integer

    题意:给出一个n和一个a  找出 $a^n + b^n = c^n$

    思路:根据费马大定理 n > 2 无解  显然 n = 0 无解

    n = 1  直接凑

    n = 2  如果是奇数 有 $a^2 + (frac{a cdot a}{2})^2 = (frac{(a cdot a) + 1}{2}) ^2$

    如果是偶数 一直除下去 知道是奇数 然后把多余的偶数加到b 和 c 上去

    或者

     1 #include <bits/stdc++.h>
     2 using namespace std; 
     3 
     4 #define ll long long
     5 #define INF 0x3f3f3f3f
     6 #define N 40010
     7 
     8 int t;
     9 ll n, a, cnt;
    10 
    11 ll arr[N][2];
    12 
    13 inline void Run()
    14 {
    15     for (int i = 3; i <= 40000; ++i)
    16     {
    17         cnt = 1;
    18         ll a = i;
    19         while ((a & 1) == 0 && a > 4)
    20         {
    21             cnt <<= 1;
    22             a >>= 1;
    23         }
    24         if (a == 4)
    25         {
    26             arr[i][0] = cnt * 3, arr[i][1] = cnt * 4;
    27         }
    28         else
    29         {
    30             ll b = a * a / 2;
    31             ll c = b + 1;
    32             arr[i][0] = b * cnt;
    33             arr[i][1] = c * cnt;
    34         }
    35     }
    36     scanf("%d", &t);
    37     while (t--)
    38     {
    39         scanf("%lld%lld", &n, &a);
    40         if (n == 0 || n >= 3)
    41         {
    42             puts("-1 -1");
    43             continue;
    44         }
    45         if (n == 1)
    46         {
    47             printf("1 %lld
    ", a + 1);
    48             continue;
    49         }
    50         printf("%lld %lld
    ", arr[a][0], arr[a][1]);
    51     }
    52 }
    53 
    54 int main()
    55 {
    56     #ifdef LOCAL
    57         freopen("Test.in", "r", stdin); 
    58     #endif
    59 
    60     Run();
    61     
    62     return 0;
    63 }
    View Code

    E - GuGu Convolution

    留坑。

    F - Neko and Inu

    留坑。

    G - Neko's loop

    题意:给出一个长度为n的数列,每个位置都有自己的权值,你有m点能量,每次可以从i走到(i+k)%n点,可以再任意时刻停止,为达到s点能量,需要起始能量为多少。

    思路:可以通过o(n)的时间处理出循环节。对于每个循环节,我们可以走完循环节或者不走完。对于不走完这部分的步数可能为m%循环节长度,也可能为m或者循环节长度。问题就转换为长度不超过限制长度的最大连续子序列,通过dp+单调队列来解决。

      1 #include<bits/stdc++.h>
      2 
      3 using namespace std;
      4 
      5 typedef long long ll;
      6 const int MOD = 1e9 + 7;
      7 const int INF = 0x3f3f3f3f;
      8 const int maxn = 1e4 + 10;
      9 
     10 int n, m, k;
     11 ll s, ans, val[maxn];
     12 vector<ll>vec;
     13 bool vis[maxn];
     14 ll sum[maxn << 1];
     15 ll que[maxn << 1];
     16 
     17 inline ll cal(int count)
     18 {
     19     int len = vec.size();
     20     for (int i = 0; i < len; ++i)
     21     {
     22         que[i] = que[i + len] = vec[i];
     23     }
     24     len <<= 1;
     25     list<ll>q;
     26     int st = 0;
     27     int ed = 0;
     28     ll res = 0;
     29     for (int i = 0; i < len; ++i)
     30     {
     31         if (i == 0)
     32         {
     33             sum[i] = que[i];
     34         }
     35         else
     36         {
     37             sum[i] = sum[i - 1] + que[i];
     38         }
     39     }
     40     for (int i = 0; i < len; ++i)
     41     {
     42         while (!q.empty() && sum[q.front()] > sum[i])
     43         {
     44             q.pop_front();
     45         }
     46         q.push_front(i);
     47         while (!q.empty() && i - q.back() > count)
     48         {
     49             q.pop_back();
     50         }
     51         res = max(res, sum[i] - sum[q.back()]);
     52     }
     53     return res;
     54 }
     55 
     56 inline ll solve()
     57 {
     58     ll mod = m % vec.size();
     59     ll circle = m / vec.size();
     60     ll sum = 0;
     61     for (auto it : vec)
     62     {
     63         sum += it;
     64     }
     65     ll max1 = cal(mod);
     66     ll max2 = cal(vec.size());
     67     max1 += max(0ll, sum) * circle;
     68     max2 += max(0LL, sum)*((circle > 2) ? circle - 1 : 0);
     69     return max(max1, max2);
     70 }
     71 
     72 inline void RUN()
     73 {
     74     int t;
     75     scanf("%d", &t);
     76     for (int cas = 1; cas <= t; ++cas)
     77     {
     78         memset(vis, false, sizeof vis);
     79         scanf("%d %lld %d %d", &n, &s, &m, &k);
     80         for (int i = 0; i < n; ++i)
     81         {
     82             scanf("%lld", val + i);
     83         }
     84         ans = 0;
     85         for (int i = 0; i < n; ++i)
     86         {
     87             if (!vis[i])
     88             {
     89                 vec.clear();
     90                 vis[i] = true;
     91                 vec.push_back(val[i]);
     92                 for (int j = (i + k) % n; j != i && !vis[j]; j = (j + k) % n)
     93                 {
     94                     vis[j] = true;
     95                     vec.push_back(val[j]);
     96                 }
     97                 ans = max(ans, solve());
     98             }
     99         }
    100         if (ans >= s) ans = 0;
    101         else ans = s - ans;
    102         printf("Case #%d: %lld
    ", cas, ans);
    103     }
    104 }
    105 
    106 int main()
    107 {
    108 #ifdef LOCAL_JUDGE
    109     freopen("Text.txt", "r", stdin);
    110 #endif // LOCAL_JUDGE
    111 
    112     RUN();
    113 
    114 #ifdef LOCAL_JUDGE
    115     fclose(stdin);
    116 #endif // LOCAL_JUDGE
    117 
    118     return 0;
    119 }
    View Code

    H - Search for Answer

    留坑。

    I - Tree and Permutation

    题意:一个序列的值为第一个点走到后面n-1个点的距离和,求n!个序列的和

    思路:对于每条边,这条边的左右端点均要走向对方。那么对于每条边的经过的次数为左右端点节点数的乘积。但是每个点都作为起点(n-1)!次,求和即可得到答案。

     1 #include<bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 typedef long long ll;
     6 const int INF = 0x3f3f3f3f;
     7 const ll INFLL = 0x3f3f3f3f3f3f3f3f;
     8 const int MOD = (int)1e9 + 7;
     9 const int maxn = (int)1e5 + 10;
    10 
    11 struct Edge {
    12     int u, v;
    13     ll w;
    14     inline Edge() {    }
    15     inline Edge(int u,int v,ll w):u(u),v(v),w(w){}
    16 };
    17 
    18 int n;
    19 ll ans;
    20 int son[maxn];
    21 vector<Edge>G[maxn];
    22 
    23 inline void Init()
    24 {
    25     ans = 0;
    26     memset(son, 0, sizeof son);
    27     for (int i = 1; i <= n; ++i)
    28     {
    29         G[i].clear();
    30     }
    31 }
    32 
    33 inline void DFS(int u, int pre)
    34 {
    35     son[u] = 1;
    36     for (auto it : G[u])
    37     {
    38         int v = it.v;
    39         if (v == pre) continue;
    40         DFS(v, u);
    41         son[u] += son[v];
    42         ans = (ans + (ll)son[v] * (n - son[v]) % MOD * it.w) % MOD;
    43     }
    44 }
    45 
    46 inline void RUN()
    47 {
    48     while (~scanf("%d", &n))
    49     {
    50         Init();
    51         for (int i = 1; i < n; ++i)
    52         {
    53             int u, v;
    54             ll w;
    55             scanf("%d %d %lld", &u, &v, &w);
    56             G[u].push_back(Edge(u, v, w));
    57             G[v].push_back(Edge(v, u, w));
    58         }
    59         DFS(1, -1);
    60         for (int i = 1; i <= n - 1; ++i)
    61         {
    62             ans = (ans * i) % MOD;
    63         }
    64         ans = (ans * 2) % MOD;
    65         printf("%lld
    ", ans);
    66     }
    67 }
    68 
    69 int main()
    70 {
    71 #ifdef LOCAL_JUDGE
    72     freopen("Text.txt", "r", stdin);
    73 #endif // LOCAL_JUDGE
    74 
    75     RUN();
    76 
    77 #ifdef LOCAL_JUDGE
    78     fclose(stdin);
    79 #endif // LOCAL_JUDGE
    80     return 0;
    81 }
    View Code

    J - YJJ's Salesman

    题意:给出若干个点 ,范围属于(0, 0) - (1e9, 1e9) 从(0, 0)  走到(1e9, 1e9),只能向上走,向右走,或者右上角走,有些点有权值,不能回头,求最后获得的最大权值

    思路:最大上升子序列的权值和 先按x排序,再对y离散化,线段树优化

      1 #include <bits/stdc++.h>
      2 using namespace std; 
      3 
      4 #define N 100010
      5 
      6 int t, n, m;
      7 int tmp[N];
      8 
      9 struct Data
     10 {
     11     int x, y, v;
     12     inline void scan()
     13     {
     14         scanf("%d%d%d", &x, &y, &v);
     15     }
     16     inline bool operator < (const Data &r) const
     17     {
     18         return x < r.x || x == r.x && y < r.y;
     19     }
     20 }arr[N];
     21 
     22 inline void Init()
     23 {
     24     for (int i = 1; i <= n; ++i) tmp[i] = arr[i].y;
     25     sort(tmp + 1, tmp + 1 + n);
     26     m = unique(tmp + 1, tmp + 1 + n) - tmp - 1;
     27 }
     28 
     29 inline int Get(int x)
     30 {
     31     return lower_bound(tmp + 1, tmp + 1 + m, x) - tmp;
     32 }
     33 
     34 struct node
     35 {
     36     int l, r;
     37     int Max;
     38     inline node() {}
     39     inline node(int l, int r, int Max) : l(l), r(r), Max(Max) {}
     40 }tree[N << 2];
     41 
     42 inline void pushup(int id)
     43 {
     44     tree[id].Max = max(tree[id << 1].Max, tree[id << 1 | 1].Max);
     45 }
     46 
     47 inline void build(int id, int l, int r)
     48 {
     49     tree[id] = node(l, r, 0);
     50     if (l == r) return;
     51     int mid = (l + r) >> 1;
     52     build(id << 1, l, mid);
     53     build(id << 1 | 1, mid + 1, r);
     54 }
     55 
     56 inline void update(int id, int pos, int val)
     57 {
     58     if (tree[id].l == tree[id].r)
     59     {
     60         tree[id].Max = max(tree[id].Max, val);
     61         return;
     62     }
     63     int mid = (tree[id].l + tree[id].r) >> 1;
     64     if (pos <= mid) update(id << 1, pos, val);
     65     else update(id << 1 | 1, pos, val);
     66     pushup(id);
     67 }
     68 
     69 int ansMax;
     70 
     71 inline void query(int id, int l, int r)
     72 {
     73     if (l > r) return;
     74     if (tree[id].l >= l && tree[id].r <= r)
     75     {
     76         ansMax = max(ansMax, tree[id].Max);
     77         return;
     78     }
     79     int mid = (tree[id].l + tree[id].r) >> 1;
     80     if (l <= mid) query(id << 1, l, r);
     81     if (r > mid) query(id << 1 | 1, l, r);
     82 }
     83 
     84 inline void Run()
     85 {
     86     scanf("%d", &t);
     87     while (t--)
     88     {
     89         scanf("%d", &n);
     90         for (int i = 1; i <= n; ++i) arr[i].scan();
     91         sort(arr + 1, arr + 1 + n); Init(); build(1, 1, n);
     92         for (int i = 1; i <= n; ++i) arr[i].y = Get(arr[i].y);
     93         vector <int> v;
     94         int ans = arr[1].v; v.push_back(1);
     95         for (int i = 2; i <= n; ++i)
     96         {
     97             if (arr[i].x != arr[i - 1].x)
     98             {
     99                 for (auto it : v)
    100                 {
    101                     update(1, arr[it].y, arr[it].v);
    102                 }
    103                 v.clear();
    104             }
    105             ansMax = 0; query(1, 1, arr[i].y - 1);
    106             ans = max(ans, ansMax + arr[i].v);
    107             //printf("%d %d %d
    ", i, ansMax, arr[i].v);
    108             arr[i].v += ansMax;
    109             v.push_back(i);
    110         }
    111         printf("%d
    ", ans);
    112     }
    113 }
    114 
    115 int main()
    116 {
    117     #ifdef LOCAL
    118         freopen("Test.in", "r", stdin); 
    119     #endif
    120 
    121     Run();
    122     
    123     return 0;
    124 }
    View Code
  • 相关阅读:
    实验四
    密码破解技术
    222
    111
    6
    5
    4
    第三次
    第二次
    第一次
  • 原文地址:https://www.cnblogs.com/Dup4/p/9535042.html
Copyright © 2020-2023  润新知