zoukankan      html  css  js  c++  java
  • 2017ACM省赛选拔赛题解

    Problem A: 聪明的田鼠

    题解:

    dp[k][i]表示走了k步,且在第i行的最大值

    最后的结果就是走了n+m-2步,且在第n行的值

    代码:

     1 #include <map>
     2 #include <set>
     3 #include <cmath>
     4 #include <queue>
     5 #include <stack>
     6 #include <cstdio>
     7 #include <string>
     8 #include <vector>
     9 #include <cstdlib>
    10 #include <cstring>
    11 #include <sstream>
    12 #include <iostream>
    13 #include <algorithm>
    14 #include <functional>
    15 using namespace std;
    16 #define rep(i,a,n) for (int i=a;i<n;i++)
    17 #define per(i,a,n) for (int i=n-1;i>=a;i--)
    18 #define pb push_back
    19 #define mp make_pair
    20 #define all(x) (x).begin(),(x).end()
    21 #define SZ(x) ((int)(x).size())
    22 typedef vector<int> VI;
    23 typedef long long ll;
    24 typedef pair<int, int> PII;
    25 const ll MOD = 1e9 + 7;
    26 const int INF = 0x3f3f3f3f;
    27 const double EPS = 1e-10;
    28 const double PI = acos(-1.0);
    29 const int MAXN = 60;
    30 // head
    31  
    32 int n, m;
    33 int a[MAXN][MAXN];
    34 int dp[MAXN * 2][MAXN];
    35  
    36 int main() {
    37     cin >> n >> m;
    38     rep(i, 1, n + 1) rep(j, 1, m + 1) cin >> a[i][j];
    39     dp[0][1] = a[1][1];
    40     rep(k, 1, n + m - 1) rep(i, max(1, k + 2 - m), n + 1) if (i <= k + 1)
    41         dp[k][i] = max(dp[k - 1][i], dp[k - 1][i - 1]) + a[i][k + 2 - i];
    42     cout << dp[n + m - 2][n] << endl;
    43     return 0;
    44 }

    Problem B: 软件安装

    题解:

    线段树区间更新,区间查询

    代码:

      1 #include <map>
      2 #include <set>
      3 #include <cmath>
      4 #include <queue>
      5 #include <stack>
      6 #include <cstdio>
      7 #include <string>
      8 #include <vector>
      9 #include <cstdlib>
     10 #include <cstring>
     11 #include <sstream>
     12 #include <iostream>
     13 #include <algorithm>
     14 #include <functional>
     15 using namespace std;
     16 #define rep(i,a,n) for (int i=a;i<n;i++)
     17 #define per(i,a,n) for (int i=n-1;i>=a;i--)
     18 #define all(x) (x).begin(),(x).end()
     19 #define pb push_back
     20 #define mp make_pair
     21 #define lson l,m,rt<<1  
     22 #define rson m+1,r,rt<<1|1 
     23 typedef long long ll;
     24 typedef vector<int> VI;
     25 typedef pair<int, int> PII;
     26 const ll MOD = 1e9 + 7;
     27 const int INF = 0x3f3f3f3f;
     28 const int MAXN = 5e4 + 7;
     29 // head
     30 
     31 int cover[MAXN << 2];
     32 int lsum[MAXN << 2], rsum[MAXN << 2], msum[MAXN << 2];
     33 
     34 void pushup(int rt, int m) {
     35     lsum[rt] = lsum[rt << 1], rsum[rt] = rsum[rt << 1 | 1];
     36     if (lsum[rt << 1] == m - (m >> 1)) lsum[rt] += lsum[rt << 1 | 1];
     37     if (rsum[rt << 1 | 1] == m >> 1) rsum[rt] += rsum[rt << 1];
     38     msum[rt] = max(max(msum[rt << 1], msum[rt << 1 | 1]), rsum[rt << 1] + lsum[rt << 1 | 1]);
     39 }
     40 
     41 void pushdown(int rt, int m) {
     42     if (cover[rt] != -1) {
     43         cover[rt << 1] = cover[rt << 1 | 1] = cover[rt];
     44         lsum[rt << 1] = rsum[rt << 1] = msum[rt << 1] = (cover[rt] ? 0 : m - (m >> 1));
     45         lsum[rt << 1 | 1] = rsum[rt << 1 | 1] = msum[rt << 1 | 1] = (cover[rt] ? 0 : m >> 1);
     46         cover[rt] = -1;
     47     }
     48 }
     49 
     50 void build(int l, int r, int rt) {
     51     cover[rt] = -1;
     52     lsum[rt] = rsum[rt] = msum[rt] = r - l + 1;
     53     if (l == r) return;
     54     int m = (l + r) >> 1;
     55     build(lson);
     56     build(rson);
     57 }
     58 
     59 void update(int L, int R, int x, int l, int r, int rt) {
     60     if (L <= l && r <= R) {
     61         cover[rt] = x;
     62         lsum[rt] = rsum[rt] = msum[rt] = (x ? 0 : r - l + 1);
     63         return;
     64     } 
     65     pushdown(rt, r - l + 1);
     66     int m = (l + r) >> 1;
     67     if (L <= m) update(L, R, x, lson);    
     68     if (R > m) update(L, R, x, rson);
     69     pushup(rt, r - l + 1);
     70 }
     71 
     72 int query(int x, int l, int r, int rt) {
     73     if (l == r) return l;
     74     pushdown(rt, r - l + 1);
     75     int m = (l + r) >> 1;
     76     if (msum[rt << 1] >= x) return query(x, lson);
     77     else if (rsum[rt << 1] + lsum[rt << 1 | 1] >= x) return m - rsum[rt << 1] + 1;
     78     else query(x, rson);
     79 }
     80 
     81 int main() {
     82     int n, m;
     83     cin >> n >> m;
     84     build(1, n, 1);
     85     while (m--) {
     86         int a, b, c;
     87         scanf("%d", &a);
     88         if (a == 1) {
     89             scanf("%d", &b);
     90             if (msum[1] < b) {
     91                 puts("0");
     92                 continue;
     93             }
     94             int ans = query(b, 1, n, 1);
     95             printf("%d
    ", ans);
     96             update(ans, ans + b - 1, 1, 1, n, 1);
     97         }
     98         else {
     99             scanf("%d%d",&b, &c);
    100             update(b, b + c - 1, 0, 1, n, 1);
    101         }
    102     }
    103     return 0;
    104 }

    Problem C: V型积木

    题解:

    最长上升子序列,枚举每个最为最低点,分别求左右两边的LIS,复杂度n³

    不过学长说可以用树状数组,nlogn就能解决,万能的树状数组。。

    代码:

     1 #include <map>
     2 #include <set>
     3 #include <cmath>
     4 #include <queue>
     5 #include <stack>
     6 #include <cstdio>
     7 #include <string>
     8 #include <vector>
     9 #include <cstdlib>
    10 #include <cstring>
    11 #include <sstream>
    12 #include <iostream>
    13 #include <algorithm>
    14 #include <functional>
    15 using namespace std;
    16 #define rep(i,a,n) for (int i=a;i<n;i++)
    17 #define per(i,a,n) for (int i=n-1;i>=a;i--)
    18 #define pb push_back
    19 #define mp make_pair
    20 #define all(x) (x).begin(),(x).end()
    21 #define SZ(x) ((int)(x).size())
    22 typedef vector<int> VI;
    23 typedef long long ll;
    24 typedef pair<int, int> PII;
    25 const ll MOD = 1e9 + 7;
    26 const int INF = 0x3f3f3f3f;
    27 const double EPS = 1e-10;
    28 const double PI = acos(-1.0);
    29 const int MAXN = 110;
    30 // head
    31  
    32 int n;
    33 int a[MAXN];
    34 int dp[MAXN];
    35  
    36 int main() {
    37     int T;
    38     cin >> T;
    39     while (T--) {
    40         cin >> n;
    41         rep(i, 0, n) scanf("%d", a + i);
    42         int ans = 0;
    43         rep(k, 0, n) {
    44             memset(dp, 0, sizeof(dp));
    45             int sum = 0, t = 0;
    46             per(i, 0, k) rep(j, i + 1, k + 1) if (a[i] > a[j]) 
    47                 dp[i] = max(dp[i], dp[j] + 1), t = max(t, dp[i]);
    48             if (t == 0) continue;
    49             sum += t;
    50             t = 0;
    51             rep(i, k + 1, n) rep(j, k, i) if (a[i] > a[j]) 
    52                 dp[i] = max(dp[i], dp[j] + 1), t = max(t, dp[i]);
    53             if (t == 0) continue;
    54             sum += t;
    55             ans = max(ans, sum + 1);
    56         }
    57         if (ans == 0) cout << "No Solution" << endl;
    58         else cout << n - ans << endl;
    59     }
    60     return 0;
    61 }

    Problem D: 最佳地址

    题解:

    最小费用流,建立一个超级源点s和超级汇点t

    coal0表示原有的发电厂,coal1表示当前要新建的发电厂

    从s到coal0连一条流量为b,费用为0的边

    从s到coal1连一条流量为sum-b,费用为0的边  因为题目说了全部供应,所以剩下的所有煤矿都要供应到新发电厂

    然后coal0和coal1都分别和每个煤矿相连,流量就是煤矿的产量a[i],费用就是c[0][i]和c[1][i]

    最后每个煤矿再连接到t,流量为a[i],费用为0

    然后跑一下最小费用流就可以了

    点的标号分别为0-m-1为煤矿   m为coal0   m+1为coal1   m+2为s   m+3为t   一共m+4个点

    代码:

      1 #include <map>
      2 #include <set>
      3 #include <cmath>
      4 #include <queue>
      5 #include <stack>
      6 #include <cstdio>
      7 #include <string>
      8 #include <vector>
      9 #include <cstdlib>
     10 #include <cstring>
     11 #include <sstream>
     12 #include <iostream>
     13 #include <algorithm>
     14 #include <functional>
     15 using namespace std;
     16 #define rep(i,a,n) for (int i=a;i<n;i++)
     17 #define per(i,a,n) for (int i=n-1;i>=a;i--)
     18 #define pb push_back
     19 #define mp make_pair
     20 #define all(x) (x).begin(),(x).end()
     21 #define SZ(x) ((int)(x).size())
     22 typedef vector<int> VI;
     23 typedef long long ll;
     24 typedef pair<int, int> PII;
     25 const ll MOD = 1e9 + 7;
     26 const int INF = 0x3f3f3f3f;
     27 const double EPS = 1e-10;
     28 const double PI = acos(-1.0);
     29 const int MAXN = 110;   //看了测试数据,m和n最大不超过100
     30 // head
     31  
     32 int n, b, m, H;
     33 int a[MAXN];
     34 int h[MAXN];
     35 int c[MAXN][MAXN];
     36  
     37 struct edge { int to, cap, cost, rev; };
     38 const int MAX_V = 1e4 + 7;
     39 int V;
     40 vector<edge> G[MAX_V];
     41 int dist[MAX_V];
     42 int prevv[MAX_V], preve[MAX_V];
     43  
     44 void add_edge(int from, int to, int cap, int cost) {
     45     G[from].pb(edge{ to,cap,cost,(int)G[to].size() });
     46     G[to].pb(edge{ from,0,-cost,(int)G[from].size() - 1 });
     47 }
     48  
     49 int min_cost_flow(int s, int t, int f) {
     50     int res = 0;
     51     while (f > 0) {
     52         memset(dist, 0x3f, sizeof(dist));
     53         dist[s] = 0;
     54         bool update = true;
     55         while (update) {
     56             update = false;
     57             rep(v, 0, V) {
     58                 if (dist[v] == INF) continue;
     59                 rep(i, 0, G[v].size()) {
     60                     edge &e = G[v][i];
     61                     if (e.cap > 0 && dist[e.to] > dist[v] + e.cost) {
     62                         dist[e.to] = dist[v] + e.cost;
     63                         prevv[e.to] = v;
     64                         preve[e.to] = i;
     65                         update = true;
     66                     }
     67                 }
     68             }
     69         }
     70         if (dist[t] == INF) return -1;
     71         int d = f;
     72         for (int v = t; v != s; v = prevv[v]) d = min(d, G[prevv[v]][preve[v]].cap);
     73         f -= d;
     74         res += d*dist[t];
     75         for (int v = t; v != s; v = prevv[v]) {
     76             edge &e = G[prevv[v]][preve[v]];
     77             e.cap -= d;
     78             G[v][e.rev].cap += d;
     79         }
     80     }
     81     return res;
     82 }
     83  
     84 int main() {
     85     int T;
     86     cin >> T;
     87     while (T--) {
     88         cin >> m >> b >> H >> n;
     89         int sum = 0;
     90         rep(i, 0, m) scanf("%d", a + i), sum += a[i];
     91         rep(i, 0, n) scanf("%d", h + i);
     92         rep(i, 0, m) scanf("%d", &c[0][i]);
     93         PII ans = mp(0, INF);
     94         rep(k, 0, n) {
     95             rep(i, 0, MAX_V) G[i].clear();
     96             rep(i, 0, m) scanf("%d", &c[1][i]);
     97             int coal0 = m, coal1 = m + 1, s = m + 2, t = m + 3;
     98             V = m + 4;
     99             add_edge(s, coal0, b, 0);
    100             add_edge(s, coal1, sum - b, 0);
    101             rep(i, 0, m) {
    102                 add_edge(coal0, i, a[i], c[0][i]);
    103                 add_edge(coal1, i, a[i], c[1][i]);
    104                 add_edge(i, t, a[i], 0);
    105             }
    106             int mcf = min_cost_flow(s, t, sum) + H + h[k];
    107             if (mcf < ans.second) ans.second = mcf, ans.first = k;
    108         }
    109         cout << ans.first + 1 << ' ' << ans.second << endl;
    110     }
    111     return 0;
    112 }

    Problem E: 寻宝

    题解:

    从0点(题目中的1,习惯从0开始,所以全都-1计算)跑一下改进版dijkstra

    当然求的不是最短路,d[i]表示从0到i的所有路线中 每条路线中的权重最小的值  的最大值

    这个只要稍微修改一下就好了 

    c[i]存的就是有c[i]个宝藏地点 可以携带i个宝藏到达那里,因为最多有k个宝藏,所以超过k的也按k算

    最后贪心模拟一下就好了

    代码:

     1 #include <map>
     2 #include <set>
     3 #include <cmath>
     4 #include <queue>
     5 #include <stack>
     6 #include <cstdio>
     7 #include <string>
     8 #include <vector>
     9 #include <cstdlib>
    10 #include <cstring>
    11 #include <sstream>
    12 #include <iostream>
    13 #include <algorithm>
    14 #include <functional>
    15 using namespace std;
    16 #define rep(i,a,n) for (int i=a;i<n;i++)
    17 #define per(i,a,n) for (int i=n-1;i>=a;i--)
    18 #define pb push_back
    19 #define mp make_pair
    20 #define all(x) (x).begin(),(x).end()
    21 #define SZ(x) ((int)(x).size())
    22 typedef vector<int> VI;
    23 typedef long long ll;
    24 typedef pair<int, int> PII;
    25 const ll MOD = 1e9 + 7;
    26 const int INF = 0x3f3f3f3f;
    27 const double EPS = 1e-10;
    28 const double PI = acos(-1.0);
    29 const int MAXN = 8010;
    30 // head
    31  
    32 const int MAX_V = MAXN;
    33 struct edge { int to, cost; };
    34 vector<edge> G[MAX_V];
    35 int d[MAX_V];
    36 int V;
    37  
    38 void dijkstra() {
    39     priority_queue<PII, vector<PII>, greater<PII> > que;
    40     d[0] = INF;
    41     que.push(PII(INF, 0));
    42  
    43     while (!que.empty()) {
    44         PII p = que.top(); que.pop();
    45         int v = p.second;
    46         if (d[v] > p.first) continue;
    47         rep(i, 0, G[v].size()) {
    48             edge e = G[v][i];
    49             if (d[e.to] < min(d[v], e.cost)) {
    50                 d[e.to] = min(d[v], e.cost);
    51                 que.push(PII(d[e.to], e.to));
    52             }
    53         }
    54     }
    55 }
    56  
    57 int n, m, k, w;
    58 int a[MAXN], c[MAXN];
    59  
    60 int main() {
    61     scanf("%d%d%d%d", &n, &m, &k, &w);
    62     V = n;
    63     rep(i, 0, k) {
    64         int t;
    65         scanf("%d", &t);
    66         a[--t] = 1;
    67     }
    68     while (m--) {
    69         int x, y, z;
    70         scanf("%d%d%d", &x, &y, &z);
    71         x--, y--;
    72         G[x].pb(edge{ y,z });
    73         G[y].pb(edge{ x,z });
    74     }
    75     dijkstra();
    76     rep(i, 0, n) if (a[i]) c[min(d[i] / w, k)]++;
    77     int sum = 0, sur = 0, ans = k;
    78     per(i, 1, k + 1) {
    79         if (c[i]) sur += c[i] - 1;
    80         else if (sur) sur--;
    81         else ans--;
    82     }
    83     cout << ans << endl;
    84     return 0;
    85 }
  • 相关阅读:
    收藏文章
    Python __func__
    Python 可变对象 & 不可变对象
    Kafka SASL ACL配置踩坑总结
    C++ 传递动态内存
    负数取反,单目运算“-”的运算
    C++重载运算符的理解
    c++ 随机函数用法
    static变量
    路由汇聚及其相关计算
  • 原文地址:https://www.cnblogs.com/baocong/p/6690546.html
Copyright © 2011-2022 走看看