• CSUST-2018集训队湖南省赛选拔赛


    省赛选拔,打之前觉得好神仙,打之中觉得这些题真tm都不错,打完之后看题解为什么这些傻逼题都没出,QAQ

    记录一些值得学习的自我感觉有意义补的题

    Day1。血崩3题

    1001 搬东西 赛后补题(血亏)

    给你2N+K个物品,可以选K个放在车上,剩下2N个自己搬,每次搬两个,消耗是两个物品的差的绝对值,求最小消耗

    标程:DP。我:贪心+DP,一个(假)结论,应该之前是做过原题的

    设dp(i,j)表示前i个物品,j个放在车上的最小消耗,答案是dp(2n+k,k),决策都是放车和不放车

    标程给的转移是选相邻两个物品或者间隔一个的物品,不过好像我猜了一下最优解一定是相邻两个一起搬

    所以dp方程就变成了:dp[i][j] = min(dp[i-1][j-1]/*表示放*/, dp[i-2][j] + (a[i]-a[i-1])/*表示搬*/)

    可能是水过去的AC代码:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<iostream>
     5 #define INF 0x3f3f3f3f
     6 #define LL long long
     7 #define debug(x) cout << "[" << x << "]" << endl
     8 using namespace std;
     9 
    10 const int mx = 1e5+25;
    11 LL dp[2*mx][25];
    12 int a[2*mx];
    13 
    14 int main(){
    15     int n, k;
    16     scanf("%d%d", &n, &k);
    17     memset(dp, INF, sizeof dp);
    18     for (int i = 1; i <= 2*n+k; i++) scanf("%d", &a[i]);
    19     sort(a+1, a+n*2+k+1);
    20     for (int i = 0; i <= k; i++) dp[i][i] = 0;
    21     for (int i = 2; i <= n*2+k; i++){
    22         for (int j = 0; j <= k; j++){
    23             if (j) dp[i][j] = min(dp[i-1][j-1], dp[i][j]);
    24             dp[i][j] = min(dp[i][j], dp[i-2][j]+a[i]-a[i-1]);
    25         }
    26     }
    27     printf("%lld
    ", dp[2*n+k][k]);
    28     return 0;
    29 }
    View Code

    1003 天气变化 / 1010 气温预测

    这两道题居然是一起出的,比赛时放了后面一题,找一个数右边最后一个的比它大的数,前面是找右边第一个比它大的数

    1010赛场上是线段树直接先往右子树再往左子树单点查询,1003更好写单调栈一下就行了

    1003代码:

    咕咕咕

    1010比赛提交代码:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<iostream>
     5 #include<stack>
     6 #define lid id << 1
     7 #define rid id << 1 | 1
     8 #define LL long long
     9 #define debug(x) cout << "[" << x << "]" << endl
    10 using namespace std;
    11 
    12 const int mx = 1e6+5;
    13 struct tree{
    14     int l, r, m;
    15 }tree[mx<<2];
    16 int a[mx];
    17 
    18 void build(int l, int r, int id){
    19     tree[id].l = l;
    20     tree[id].r = r;
    21     if (l == r){
    22         tree[id].m = a[l];
    23         return;
    24     }
    25     int mid = (l+r)>>1;
    26     build(l, mid, lid);
    27     build(mid+1, r, rid);
    28     tree[id].m = max(tree[lid].m, tree[rid].m);
    29 }
    30 
    31 int query(int id, int x, int i){
    32     if (tree[id].m <= x) return i;
    33     if (tree[id].l == tree[id].r) return tree[id].l;
    34     if (x < tree[rid].m) return query(rid, x, i);
    35     else return query(lid, x, i);
    36 }
    37 
    38 int main(){
    39     int n;
    40     scanf("%d", &n);
    41     for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    42     build (1, n, 1);
    43     for (int i = 1; i <= n; i++){
    44         int ans = query(1, a[i], i);
    45         if (ans <= i) ans = i;
    46         if (i == 1) printf("%d", ans-i);
    47         else printf(" %d", ans-i);
    48     }
    49     printf("
    ");
    50     return 0;
    51 }
    View Code

    1009 模和最大

    给一个数列a,对每个a[i]找一个j != i,使得(a[i]+a[j])%p最大,输出这个值

    数据保证a[i] < p

    通过小于p可以知道任意两个数的和不超过2p,二分找加起来小于p的最大值,再取一个最大的值相加,取max一定是正解

    需要处理一下边界各种细节,赛场上的代码比较乱,也不改了,能出的快就行

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<iostream>
     5 #define LL long long
     6 #define debug(x) cout << "[" << x << "]" << endl
     7 using namespace std;
     8 
     9 const int mx = 1e6+5;
    10 int ans[mx], b[mx];
    11 
    12 struct node{
    13     int id, num;
    14     bool operator < (const node& a) const{
    15         return num < a.num;
    16     }
    17 }a[mx];
    18 
    19 int main(){
    20     int n, k;
    21     scanf("%d%d", &n, &k);
    22     for (int i = 1; i <= n; i++) {
    23         scanf("%d", &a[i].num);
    24         a[i].id = i;
    25     }
    26     sort(a+1, a+n+1);
    27     for (int i = 1; i <= n; i++) b[i] = a[i].num;
    28     for (int i = 1; i <= n; i++){
    29         int s = upper_bound(b+1, b+n+1, k-1-b[i])-b;
    30         if (b[s] > k-1-b[i]) s--;
    31         if (!s) s = n;
    32         if (i == s) s--;
    33         if (!s) s = n;
    34         ans[a[i].id] = (b[i]+b[s])%k;
    35         if (i == n) ans[a[i].id] = max(ans[a[i].id], (b[n]+b[n-1])%k);
    36         else ans[a[i].id] = max(ans[a[i].id], (b[i]+b[n])%k);
    37     }
    38     for (int i = 1; i <= n; i++){
    39         if (i == 1) printf("%d", ans[i]);
    40         else printf(" %d", ans[i]);
    41     }
    42     printf("
    ");
    43     return 0;
    44 }
    View Code

    Day2 5题 比第一次简单好歹还能抢救一下我

    赛前还听说这场全都是神仙题,吓死了QAQ

    1011 神秘群岛

    给一棵树,边是双向的且权值不同,每条边每个方向只能走一次,q次询问u到v能走到的最大边权

    n,q 1e5

    画个图可以发现除了v到u的简单路径,其它所有的边权都能收集到,跟LCA求链长的区别就是在dfs的时候多算了一条反向边

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<vector>
     5 #include<iostream>
     6 #define INF 0x3f3f3f3f
     7 #define LL long long
     8 #define debug(x) cout << "[" << x << "]" << endl
     9 using namespace std;
    10 
    11 const int mx = 1e5+5;
    12 int d[mx][2], p[mx][30], pa[mx], rk[mx];
    13 int n;
    14 
    15 struct edge{
    16     int v, w, b;
    17     edge(int v = 0, int w = 0, int b = 0): v(v), w(w), b(b){}
    18 };
    19 vector<edge> G[mx];
    20 
    21 void dfs(int u, int fa, int cnt){
    22     pa[u] = fa;
    23     rk[u] = cnt;
    24     int len = G[u].size();
    25     for (int i = 0; i < len; i++){
    26         int v = G[u][i].v;
    27         if (v != fa){
    28             d[v][0] = d[u][0]+G[u][i].w;
    29             d[v][1] = d[u][1]+G[u][i].b;
    30             dfs(v, u, cnt+1);
    31         }
    32     }
    33 }
    34 
    35 void LCA(){
    36     for (int i = 1; i <= n; i++){
    37         p[i][0] = pa[i];
    38         for (int j = 1; (1<<j) <= n; j++) p[i][j] = -1;
    39     }
    40     for (int j = 1; (1<<j) <= n; j++)
    41         for (int i = 1; i <= n; i++)
    42             if (p[i][j-1] != -1) p[i][j] = p[p[i][j-1]][j-1];
    43 }
    44 
    45 int query(int x, int y){
    46     if (rk[x] < rk[y]) swap(x, y);
    47     int k;
    48     for (k = 0; (1<<(k+1)) <= rk[x]; k++);
    49     for (int i = k; i >= 0; i--)
    50         if (rk[x] - (1<<i) >= rk[y]) x = p[x][i];
    51     if (x == y) return x;
    52     for (int i = k; i >= 0; i--){
    53         if (p[x][i] != -1 && p[x][i] != p[y][i]){
    54             x = p[x][i];
    55             y = p[y][i];
    56         }
    57     }
    58     return p[x][0];
    59 }
    60 
    61 
    62 int main(){
    63     int t, q, u, v;
    64     scanf("%d", &t);
    65     while (t--){
    66         int a, b;
    67         LL sum = 0;
    68         scanf("%d", &n);
    69         memset(d, 0, sizeof d);
    70         for (int i = 0; i <= n; i++) G[i].clear();
    71         for (int i = 1; i < n; i++){
    72             scanf("%d%d%d%d", &u, &v, &a, &b);
    73             G[u].push_back(edge(v, a, b));
    74             G[v].push_back(edge(u, b, a));
    75             sum += (a+b);
    76         }
    77         dfs(1, -1, 0);
    78         LCA();
    79         scanf("%d", &q);
    80         while (q--){
    81             scanf("%d%d", &u, &v);
    82             int c = query(u, v);
    83             printf("%lld
    ", sum-(d[u][0]+d[v][1]-d[c][1]-d[c][0]));
    84         }
    85     }
    86     return 0;
    87 }
    View Code

    1012 笑脸

    一个只有:)(的字符串,:)看做笑脸,现在可以将一个前缀翻转一次,求最多能得到多少个笑脸

    跑一遍笑脸和反笑脸【(:】的前缀和,枚举断点,要注意边界情况,WA了好几次。。。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<iostream>
     5 #define LL long long
     6 #define debug(x) cout << "[" << x << "]" << endl
     7 using namespace std;
     8 
     9 const int mx = 2e5+10;
    10 char s[mx];
    11 int a[mx], b[mx];
    12 
    13 int main(){
    14     int n;
    15     scanf("%d%s", &n, s+1);
    16     for (int i = 1; i <= n; i++){
    17         if (s[i-1] == ':' && s[i] == ')') a[i] = a[i-1]+1;
    18         else a[i] = a[i-1];
    19         if (s[i-1] == '(' && s[i] == ':') b[i] = b[i-1]+1;
    20         else b[i] = b[i-1];
    21     }
    22     int ans = a[n];
    23     for (int i = n; i >= 0; i--){
    24         if (s[i] == ':' && s[1] == ':') {
    25             ans = max(ans, a[n]-a[i]+b[i]);
    26             continue;
    27         }
    28         else {
    29             if (s[i] == ':' && s[i+1] == ')' && s[1] != ':'){
    30                 ans = max(ans, a[n]-a[i]+b[i]-1);
    31                 continue;
    32             }
    33             if (s[i] != ':' && s[1] == ':' && s[i+1] == ')'){
    34                 ans = max(ans, a[n]-a[i]+b[i]+1);
    35                 continue;
    36             }
    37         }
    38         ans = max(ans, a[n]-a[i]+b[i]);
    39     }
    40     printf("%d
    ", ans);
    41     return 0;
    42 }
    View Code

  • 相关阅读:
    表单校验神器
    插入排序
    数组去重的几种常使用的方式
    day44 mysql高级部分内容
    day43 多表查询和pymysql
    day42 字段的增删改查详细操作
    day41 mysql详细操作
    day40 mysql数据类型
    day39 mysql数据库基本操作
    day37 异步回调和协程
  • 原文地址:https://www.cnblogs.com/QAQorz/p/9460661.html
Copyright © 2020-2023  润新知