2018中国大学生程序设计竞赛 - 网络选拔赛 Solution

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\n", 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], " \n"[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], " \n"[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\n", a + 1);
48             continue;
49         }
50         printf("%lld %lld\n", 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\n", 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\n", 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\n", i, ansMax, arr[i].v);
108             arr[i].v += ansMax;
109             v.push_back(i);
110         }
111         printf("%d\n", 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

 

posted @ 2018-08-25 19:11  Dup4  阅读(407)  评论(0编辑  收藏  举报