2018 Multi-University Training Contest 10 Solution

A - Problem A.Alkane

留坑。

 

B - Problem B. Beads

留坑。

 

C - Problem C. Calculate

留坑。

 

D - Problem D. Permutation

留坑。

 

E - Problem E. TeaTree

题意:每个点会存下任意两个以他为LCA的点对的GCD,求每个点存的GCD的最大值

思路:DSU on tree  用 set 维护子树中的因子,对于重儿子不要处理多次 每次查找的时候,枚举轻儿子中的因子

还有一种线段树合并的写法

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 
  4 #define N 100010
  5 
  6 int n;
  7 vector <int> G[N], num[N];
  8 set <int> s;  
  9 int sz[N], son[N], cnt[N], cnt2[N], arr[N], ans[N], Max;
 10 bool isbig[N];  
 11 
 12 void Init()
 13 {
 14     for (int i = 1; i <= 100000; ++i)
 15     {
 16         int limit = sqrt(i); 
 17         for (int j = 1; j < limit; ++j) if (i % j == 0)
 18         {
 19             num[i].push_back(j);
 20             num[i].push_back(i / j);
 21         }
 22         if (i % limit == 0) 
 23         {
 24             num[i].push_back(limit);
 25             if (limit * limit != i) num[i].push_back(i / limit); 
 26         } 
 27     }
 28 }
 29 
 30 void DFS(int u)
 31 {
 32     sz[u] = 1; 
 33     for (auto v : G[u]) 
 34     {
 35         DFS(v); sz[u] += sz[v]; 
 36         if (son[u] == -1 || sz[v] > sz[son[u]]) son[u] = v; 
 37     } 
 38 }
 39 
 40 void update(int u)  
 41 {
 42     for (auto it : num[arr[u]]) ++cnt[it];  
 43     for (auto v : G[u]) if (!isbig[v]) update(v);  
 44 }
 45 
 46 void work(int u, int fa)
 47 {
 48     for (auto it : num[arr[u]]) s.insert(it);
 49     for (auto v : G[u]) if (!isbig[v]) work(v, fa); 
 50 } 
 51 
 52 void query(int u)
 53 {
 54     for (auto v : G[u]) if (!isbig[v]) 
 55     {
 56         s.clear(); 
 57         work(v, u);
 58         for (auto it : s) if (cnt[it] >= 1 || cnt2[it] >= 1) Max = max(Max, it);
 59         for (auto it : s) ++cnt2[it];
 60     } 
 61     for (auto it : num[arr[u]]) if (cnt[it] >= 1 || cnt2[it] >= 1) Max = max(Max, it); 
 62 } 
 63 
 64 void clear(int u)
 65 {
 66     for (auto it : num[arr[u]]) cnt[it] = cnt2[it] = 0;
 67     for (auto v : G[u]) clear(v);
 68 }
 69  
 70 void DSU(int u)
 71 { 
 72     for (auto v : G[u]) if (v != son[u]) DSU(v); 
 73     if (son[u] != -1) { isbig[son[u]] = 1; DSU(son[u]); }
 74     Max = -1; query(u); 
 75     ans[u] = Max;   
 76     if (isbig[u]) update(u);  
 77     if (son[u] != -1) isbig[son[u]] = 0; 
 78     if (!isbig[u]) clear(u);   
 79 }
 80 
 81 int main()
 82 {
 83     Init();
 84     while (scanf("%d", &n) != EOF)
 85     {
 86         for (int i = 1; i <= n; ++i) G[i].clear(); 
 87         memset(son, -1, sizeof son);
 88         memset(cnt, 0, sizeof cnt);
 89         memset(cnt2, 0, sizeof cnt2);
 90         Max = -1; s.clear();
 91         for (int i = 2, u; i <= n; ++i)
 92         {
 93             scanf("%d", &u);
 94             G[u].push_back(i);
 95         }
 96         for (int i = 1; i <= n; ++i) scanf("%d", arr + i);
 97         DFS(1); DSU(1);
 98         for (int i = 1; i <= n; ++i) printf("%d\n", ans[i]);
 99     }
100     return 0;
101 }
View Code
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define N 100010
 5 vector <int> num[N], G[N];
 6 
 7 int n;
 8 int arr[N], rt[N], ans[N];
 9 
10 void Init()
11 {
12     for (int i = 1; i <= 100000; ++i) for (int j = i; j <= 100000; j += i)
13         num[j].push_back(i);
14 }
15 
16 struct SEG
17 {
18     #define M N * 400
19     int lson[M], rson[M], c[M], cnt; 
20     void init() { cnt = 0; }
21     void pushup(int id) { c[id] = max(c[lson[id]], c[rson[id]]); }
22     void update(int &x, int l, int r, int pos)
23     {
24         if (!x) x = ++cnt;
25         if (l == r) { c[x] = pos; return; }
26         int mid = (l + r) >> 1;
27         pos <= mid ? update(lson[x], l, mid, pos) : update(rson[x], mid + 1, r, pos);
28         pushup(x);
29     }
30     int merge(int u, int v, int &sum)
31     {
32         if (!u || !v) return u | v;
33         if (c[u] == c[v]) sum = max(sum, c[u]); 
34         if (lson[u] | lson[v]) lson[u] = merge(lson[u], lson[v], sum);
35         if (rson[u] | rson[v]) rson[u] = merge(rson[u], rson[v], sum);  
36         return u;
37     }
38 }seg;
39 
40 void DFS(int u)
41 {
42     ans[u] = -1;
43     for (auto v : G[u])
44     {
45         DFS(v);
46         seg.merge(rt[u], rt[v], ans[u]); 
47     }
48 }
49 
50 void Run()
51 {
52     Init();
53     while (scanf("%d", &n) != EOF)
54     {
55         seg.init();
56         for (int i = 2, u; i <= n; ++i)
57         {
58             scanf("%d", &u);
59             G[u].push_back(i);
60         }
61         for (int i = 1; i <= n; ++i) scanf("%d", arr + i);
62         for (int i = 1; i <= n; ++i) for (auto it : num[arr[i]]) seg.update(rt[i], 1, 100000, it);  
63         DFS(1);
64         for (int i = 1; i <= n; ++i) printf("%d\n", ans[i]);
65     }
66 }
67 
68 int main()
69 {
70     #ifdef LOCAL
71         freopen("Test.in", "r", stdin);
72     #endif 
73 
74     Run();
75     return 0;
76 
77 }
View Code

 

F - Problem F. NewNippori

留坑。

 

G - Problem G. Cyclic

打表找规律即可

$F[n] = (n - 2) * F[n - 1] + (n - 1) * F[n - 2] + (i \& 1 ? 1 : -1)$

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define N 100010
 5 #define ll long long
 6 
 7 const ll MOD = 998244353;
 8 
 9 ll arr[N];
10 
11 int main()
12 {
13     arr[4] = 1, arr[5] = 8;
14     for (int i = 6; i <= 100000; ++i) arr[i] = ((i - 2) * arr[i - 1] % MOD + (i - 1) * arr[i - 2] % MOD + ((i & 1) ? 1 : -1) + MOD) % MOD;
15     int t; scanf("%d", &t);
16     while (t--)
17     {
18         int n;
19         scanf("%d", &n);
20         printf("%lld\n", arr[n]);
21     }
22 }
View Code

 

H - Problem H. Pow

水。

import java.util.Scanner;
import java.math.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int t = in.nextInt();
        while (t-- != 0)
        {
            int n = in.nextInt();
            System.out.println(BigInteger.valueOf(2).pow(n));
        }
    }
}
View Code

 

I - Problem I. Count

题意:求$\sum_{i = 1} ^ {i = n} \sum_{j = 1} ^ {j = i - 1} [gcd(i + j, i - j) == 1]$

思路:找规律。如果是奇数就加上$\frac {\varphi(n)}{2}   否则加上 \varphi(n)$

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 typedef long long ll;
 6 const int MAXN = 20000000;
 7 bool check[MAXN + 10];
 8 
 9 ll ans[MAXN + 10];
10 int phi[MAXN + 10];
11 int prime[MAXN + 10];
12 int tot;
13 
14 void phi_ans_prime_table() {
15     memset(check, false, sizeof check);
16     phi[1] = 1;
17     tot = 0;
18     for(int i = 2; i <= MAXN; ++i)
19     {
20         if(!check[i])
21         {
22             prime[tot++] = i;
23             phi[i] = i - 1;
24         }
25         for(int j = 0; j < tot; ++j)
26         {
27             if(i * prime[j] > MAXN) break;
28             check[i * prime[j]] = true;
29             if(i % prime[j] == 0)
30             {
31                 phi[i * prime[j]] = phi[i] * prime[j];
32                 break;
33             }
34             else
35             {
36                 phi[i * prime[j]] = phi[i] * (prime[j] - 1);
37             }
38         }
39         if(i & 1) ans[i] = ans[i - 1] + phi[i] / 2;
40         else ans[i] = ans[i - 1] + phi[i];
41     }
42 }
43 
44 int main() {
45     phi_ans_prime_table();
46     int t;
47     scanf("%d", &t);
48     while(t--)
49     {
50         int n;
51         scanf("%d", &n);
52         printf("%lld\n", ans[n]);
53     }    
54     return 0;
55 }
View Code

 

J - Problem J. CSGO

题意:有n把主武器和m把副武器,每把武器有k种属性,选取一把主武器和副武器,求题中式子最大值

思路:对于没种属性又有加减两种状态,枚举每把武器的每种属性的加减状态,求最大值

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 typedef long long ll;
 6 
 7 const ll INFLL = 0x3f3f3f3f3f3f3f3f;
 8 const int maxn = 1e5 + 10;
 9 
10 ll arr[maxn][10], brr[maxn][10];
11 ll crr[maxn];
12 
13 int n, m, k;
14 
15 void RUN()
16 {
17     int t;
18     scanf("%d", &t);
19     while (t--)
20     {
21         scanf("%d %d %d", &n, &m, &k);
22         for (int i = 1; i <= n; ++i) for (int j = 0; j <= k; ++j) scanf("%lld", &arr[i][j]);
23         for (int i = 1; i <= m; ++i) for (int j = 0; j <= k; ++j) scanf("%lld", &brr[i][j]);
24         memset(crr, 0, sizeof crr);
25         ll ans = 0;
26         int limit = (1 << k);
27         for (int i = 1; i <= n; ++i)
28         {
29             for (int S = 0; S < limit; ++S)
30             {
31                 ll tmp = arr[i][0];
32                 for (int j = 0; j < k; ++j)
33                 {
34                     if (S & (1 << j))
35                     {
36                         tmp += arr[i][j + 1];
37                     }
38                     else
39                     {
40                         tmp -= arr[i][j + 1];
41                     }
42                 }
43                 crr[S] = max(crr[S], tmp);
44             }
45         }
46 
47         for (int i = 1; i <= m; ++i)
48         {
49             for (int S = 0; S < limit; ++S)
50             {
51                 ll tmp = brr[i][0];
52                 for (int j = 0; j < k; ++j)
53                 {
54                     if (S & (1 << j))
55                     {
56                         tmp += brr[i][j + 1];
57                     }
58                     else
59                     {
60                         tmp -= brr[i][j + 1];
61                     }
62                 }
63                 ans = max(ans, tmp + crr[limit - 1 - S]);
64             }
65         }
66         printf("%lld\n", ans);
67     }
68 }
69 
70 int main()
71 {
72 #ifdef LOCAL_JUDGE
73     freopen("Text.txt", "r", stdin);
74 #endif // LOCAL_JUDGE
75 
76     RUN();
77 
78 #ifdef LOCAL_JUDGE
79     fclose(stdin);
80 #endif // LOCAL_JUDGE
81     return 0;
82 }
View Code
#include <bits/stdc++.h>
using namespace std;

#define N 100010
#define ll long long
#define INF 0x3f3f3f3f3f3f3f3f

int t, n, m, K;

struct node
{
    int x[10];
    void scan(int vis)
    {
        scanf("%d", x + vis);
        for (int i = 2; i <= K + 1; ++i) scanf("%d", x + i); 
    }
}a[N], b[N];

void Run()
{
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d%d%d", &n, &m, &K);
        for (int i = 1; i <= n; ++i) a[i].scan(0);
        for (int i = 1; i <= m; ++i) b[i].scan(1);
        ll res = 0;
        for (int i = 0; i < (1 << (K + 2)); ++i) 
        {
            bitset <7> bit; bit = i;
            ll Max[2] = { -INF, -INF };
            ll Min[2] = { INF, INF };
            for (int j = 1; j <= n; ++j)
            {
                ll tmp = 0;
                for (int k = 0; k <= K + 1; ++k)
                    tmp += a[j].x[k] * (bit[k] ? 1 : -1);
                Max[0] = max(Max[0], tmp);
                Min[0] = min(Min[0], tmp);
            }
            for (int j = 1; j <= m; ++j)
            {
                ll tmp = 0;
                for (int k = 0; k <= K + 1; ++k)
                    tmp += b[j].x[k] * (bit[k] ? 1 : -1); 
                Max[1] = max(Max[1], tmp);
                Min[1] = min(Min[1], tmp); 
            } 
            res = max(res, max(Max[0] - Min[1], Max[1] - Min[0]));
        }
        printf("%lld\n", res);
    }
}

int main()
{
    #ifdef LOCAL
        freopen("Test.in", "r", stdin); 
    #endif 

    Run();
    return 0;

}
View Code

 

 

K - Problem K. Pow2

留坑。

 

L - Problem L.Videos

题意:每天有n个小时,有m部电影,k个人,每部电影只能被一个人看,得到w快乐值,电影种类有AB两种,同一人连着看同种电影要减去W快乐值,如何安排使得快乐值最大

思路:将一部电影拆成两个点 S 和 T 流为1,费用为-w, 电影与电影之间如果是可以连着看的,就连边,如果是同种类,费用就是W, 否则就是0,流为1,源点练出来加一个点,流量为k,限制为k个人

  1 #include<bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 const int INF = 0x3f3f3f3f;
  6 const int maxn = 1e4 + 10;
  7 const int maxm = 1e5 + 10;
  8 
  9 struct Edge{
 10     int to, nxt, cap, flow, cost;
 11 }edge[maxm];
 12 
 13 int head[maxn], tot;
 14 int pre[maxn], dis[maxn];
 15 bool vis[maxn];
 16 int N;
 17 
 18 void Init(int n)
 19 {
 20     N = n;
 21     tot = 0;
 22     for(int i = 0; i < n; ++i) head[i] = -1;
 23 }
 24 
 25 void addedge(int u, int v, int cap, int cost)
 26 {
 27     edge[tot].to = v;
 28     edge[tot].cap = cap;
 29     edge[tot].cost = cost;
 30     edge[tot].flow = 0;
 31     edge[tot].nxt = head[u];
 32     head[u] = tot++;
 33 
 34     edge[tot].to = u;
 35     edge[tot].cap = 0;
 36     edge[tot].cost = -cost;
 37     edge[tot].flow = 0;
 38     edge[tot].nxt = head[v];
 39     head[v] = tot++;
 40 }
 41 
 42 bool SPFA(int s,int t)
 43 {
 44     queue<int>q;
 45     for(int i = 0; i < N; ++i) dis[i] = INF, pre[i] = -1, vis[i] = false;
 46     dis[s] = 0;
 47     vis[s] = true;
 48     q.push(s);
 49     while(!q.empty())
 50     {
 51         int u = q.front();
 52         q.pop();
 53         vis[u] = false;
 54         for(int i = head[u]; ~i; i = edge[i].nxt)
 55         {
 56             int v = edge[i].to;
 57             if(edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost)
 58             {
 59                 dis[v] = dis[u] + edge[i].cost;
 60                 pre[v] = i;
 61                 if(!vis[v])
 62                 {
 63                     vis[v] = true;
 64                     q.push(v);
 65                 }
 66             }
 67         }
 68     }
 69     if(pre[t] == -1) return false;
 70     else return true;
 71 }
 72 
 73 int minCostMaxflow(int s,int t, int &cost)
 74 {
 75     int flow = 0;
 76     cost = 0;
 77     while(SPFA(s, t))
 78     {
 79         int Min = INF;    
 80         for(int i = pre[t]; ~i; i = pre[edge[i ^ 1].to])
 81         {
 82             if(Min > edge[i].cap - edge[i].flow)
 83             {
 84                 Min = edge[i].cap - edge[i].flow;
 85             }
 86         }
 87         for(int i = pre[t]; ~i; i = pre[edge[i ^ 1].to])
 88         {
 89             edge[i].flow += Min;
 90             edge[i ^ 1].flow -= Min;
 91             cost += edge[i].cost * Min;
 92         }
 93         flow += Min;
 94     }
 95     return flow;
 96 }
 97 
 98 struct node{
 99     int si, ti, wi, op;
100 }arr[maxn];
101 
102 int n, m, K, W;
103 
104 int main()
105 {
106     int t;
107     scanf("%d", &t);
108     while(t--)
109     {
110         scanf("%d %d %d %d", &n, &m, &K, &W);
111         for(int i = 1; i <= m; ++i) scanf("%d %d %d %d", &arr[i].si, &arr[i].ti, &arr[i].wi, &arr[i].op);
112         Init(2 * m + 3);
113         addedge(0, 2 * m + 1, K, 0);
114         for(int i = 1; i <= m; ++i) addedge(2 * m + 1, 2 * i - 1, 1, 0);
115         for(int i = 1; i <= m; ++i) addedge(2 * i - 1, 2 * i, 1, -arr[i].wi);
116         for(int i = 1; i <= m; ++i) addedge(2 * i, 2 * m + 2, 1, 0);
117         for(int i = 1; i <= m; ++i)
118         {
119             for(int j = 1; j <= m; ++j)
120             {
121                 if(i == j) continue;
122                 if(arr[i].ti <= arr[j].si)
123                 {
124                     if(arr[i].op == arr[j].op)
125                     {
126                         addedge(2 * i, 2 * j - 1, 1, W);
127                     }
128                     else 
129                     {
130                         addedge(2 * i, 2 * j - 1, 1, 0);
131                     }
132                 }
133             }
134         }
135         int cost = 0;
136         minCostMaxflow(0, 2 * m + 2, cost);
137         printf("%d\n", -cost);
138     }
139     return 0;
140 }
View Code

 

转载于:https://www.cnblogs.com/Dup4/p/9806476.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值