• 2017 ZSTU寒假排位赛 #4


      题目链接:https://vjudge.net/contest/148543#overview

      A题:n个罪犯,每个人有一个犯罪值,现在要从里面选出连续的c个人,每个人的犯罪值都不能超过t,问选法的种类数。O(n)xjbg一下即可:

     1 #include <stdio.h>
     2 #include <algorithm>
     3 #include <string.h>
     4 #include <map>
     5 #include <set>
     6 #include <vector>
     7 #include <queue>
     8 #include <iostream>
     9 using namespace std;
    10 const int N = 200000 + 5;
    11 typedef long long ll;
    12 typedef pair<int,int> pii;
    13 
    14 int a[N];
    15 
    16 int main()
    17 {
    18     int n,t,c;
    19     cin >> n >> t >> c;
    20     ll ans = 0;
    21     int cnt = 0;
    22     for(int i=1;i<=n;i++)
    23     {
    24         int temp;scanf("%d",&temp);
    25         if(temp <= t) cnt++;
    26         else
    27         {
    28             if(cnt >= c) ans += cnt - c + 1;
    29             cnt = 0;
    30         }
    31     }
    32     if(cnt >= c) ans += cnt - c + 1;
    33     cout << ans << endl;
    34     return 0;
    35 }
    A

      B题:n个数字,从中选出不重叠的k段数字,每段的长度都为m,问最大的和。因为n是5000,所以很明显的开个二维数组n方dp一下即可:

     1 #include <stdio.h>
     2 #include <algorithm>
     3 #include <string.h>
     4 #include <map>
     5 #include <set>
     6 #include <vector>
     7 #include <queue>
     8 #include <iostream>
     9 using namespace std;
    10 const int N = 5000 + 5;
    11 typedef long long ll;
    12 typedef pair<int,int> pii;
    13 
    14 ll pre[N];
    15 ll dp[N][N];
    16 
    17 int main()
    18 {
    19     int n,m,k;
    20     cin >> n >> m >> k;
    21     for(int i=1;i<=n;i++)
    22     {
    23         int x;
    24         scanf("%d",&x);
    25         pre[i] = pre[i-1] + x;
    26     }
    27     for(int i=m;i<=n;i++)
    28     {
    29         for(int j=1;j<=k;j++)
    30         {
    31             dp[i][j] = max(dp[i-1][j], dp[i-m][j-1] + pre[i] - pre[i-m]);
    32         }
    33     }
    34     cout << dp[n][k] << endl;
    35     return 0;
    36 }
    B

      

      C题:给一个距离矩阵,问是否可能构成一棵树。做法是克鲁斯卡尔以后dfs一遍看看距离矩阵是否相等即可。仔细想想还是挺妙的。代码如下(写的有点挫):

     1 #include <stdio.h>
     2 #include <algorithm>
     3 #include <string.h>
     4 #include <map>
     5 #include <set>
     6 #include <vector>
     7 #include <queue>
     8 #include <iostream>
     9 using namespace std;
    10 const int N = 2000 + 5;
    11 typedef long long ll;
    12 typedef pair<int,int> pii;
    13 
    14 int root[N],cnt,vis[N],last[N];
    15 int n,G[N][N],d[N][N];
    16 vector<pii> graph[N];
    17 void init() {for(int i=1;i<=n;i++) root[i] = i;}
    18 int find(int x) {return x == root[x] ? x : root[x] = find(root[x]);}
    19 void connect(int x,int y,int w)
    20 {
    21     int rx = find(x);
    22     int ry = find(y);
    23     if(rx != ry)
    24     {
    25         root[rx] = ry;
    26         //d[x][y] = d[y][x] = w;
    27         graph[x].push_back(pii(y,w));
    28         graph[y].push_back(pii(x,w));
    29         cnt--;
    30     }
    31 }
    32 struct edge
    33 {
    34     int u,v,w;
    35     bool operator < (const edge & temp) const
    36     {
    37         return w > temp.w;
    38     }
    39 };
    40 
    41 void dfs(int u,int fa)
    42 {
    43     for(int i=0;i<graph[u].size();i++)
    44     {
    45         pii p = graph[u][i];
    46         int v = p.first;
    47         int w = p.second;
    48         if(v == fa) continue;
    49         last[v] = last[u] + w;
    50         dfs(v,u);
    51     }
    52 }
    53 
    54 int main()
    55 {
    56     scanf("%d",&n);
    57     for(int i=1;i<=n;i++)
    58     {
    59         for(int j=1;j<=n;j++)
    60         {
    61             scanf("%d",&G[i][j]);
    62             if(i == j && G[i][j]) return 0*puts("NO");
    63         }
    64     }
    65     for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(G[i][j] != G[j][i] || i!=j && G[i][j] == 0) return 0*puts("NO");
    66     priority_queue<edge> Q;
    67     for(int i=1;i<=n;i++)
    68     {
    69         for(int j=1;j<i;j++)
    70         {
    71             Q.push((edge){i,j,G[i][j]});
    72         }
    73     }
    74     cnt = n; init();
    75     for(;cnt > 1;)
    76     {
    77         edge e = Q.top();Q.pop();
    78         connect(e.u, e.v, e.w);
    79     }
    80     //for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) printf("%d%c",d[i][j],j==n?'
    ':' ');
    81     for(int i=1;i<=n;i++)
    82     {
    83         last[i] = 0;
    84         dfs(i,-1);
    85         for(int j=1;j<=n;j++)
    86         {
    87             if(j == i) continue;
    88             if(last[j] != G[i][j]) return 0*puts("NO");
    89         }
    90     }
    91     puts("YES");
    92     return 0;
    93 }
    C

      D题:给两个部分的字符串,分别重复n次和m次(最终长度相等),问有多少位置字符是不同的。只需要比较一个lcm里面的长度是肯定的,但暴力做肯定T。一个lcm中,考虑到只有pos%gcd这些位置需要比较。那么就可以线性的做出来了。最后扩大相应倍数即可。代码如下:

     1 #include <stdio.h>
     2 #include <algorithm>
     3 #include <string.h>
     4 #include <map>
     5 #include <set>
     6 #include <vector>
     7 #include <queue>
     8 #include <iostream>
     9 using namespace std;
    10 const int N = 1000000 + 5;
    11 typedef long long ll;
    12 typedef pair<int,int> pii;
    13 
    14 ll n,m;
    15 char a[N],b[N];
    16 int vis[N][30];
    17 
    18 int main()
    19 {
    20     cin >> n >> m;
    21     scanf("%s%s",a+1,b+1);
    22     int lena = strlen(a+1);
    23     int lenb = strlen(b+1);
    24     int g = __gcd(lena,lenb);
    25     ll lcm = (ll)lena / g * lenb;
    26     ll ans = 0;
    27     for(int i=1;i<=lena;i++) vis[i%g][a[i]-'a']++;
    28     for(int i=1;i<=lenb;i++) ans += vis[i%g][b[i]-'a'];
    29     cout << 1LL*lena * n / lcm * (lcm - ans) << endl;
    30     return 0;
    31 }
    D

      E题,看了一会没怎么明白题意,暂时放过吧。

  • 相关阅读:
    Semaphore类
    我的java学习之路五:java的循环和条件语句
    我的java学习之路四:java的基础类型和变量
    第一节 线性表
    我的java学习之路三:java的类与对象
    我的Java学习之路二:Java基础语法
    算法分析一:基本定义
    我的java学习之路一:java的安装以及环境配置
    【2019 CCPC 江西省赛】Cotree 树重心
    【2018 icpc 南京站】G
  • 原文地址:https://www.cnblogs.com/zzyDS/p/6341320.html
Copyright © 2020-2023  润新知