ZJCPC2022 第19届 浙江省赛The 19th Zhejiang Provincial Collegiate Programming Contest(CBALGMIF 8题)

Posted 小哈里

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ZJCPC2022 第19届 浙江省赛The 19th Zhejiang Provincial Collegiate Programming Contest(CBALGMIF 8题)相关的知识,希望对你有一定的参考价值。

文章目录

补题链接:https://codeforces.com/gym/103687

C.JB Wants to Earn Big Money

题意:

  • 有 n 个人想买一些股票,m 个人想卖一些股票。每个人都会给出一个价格。
  • 系统将确定最终价格 x。对于想买一些股票的人,如果他给出的价格不低于x,他就会加入交易。对于想卖掉部分股份的人,如果他给出的价格不高于x,他就会加入交易。
  • 求可以加入交易的人数。

思路:

  • 扫一遍序列,判断是否满足条件即可。
#include<bits/stdc++.h>
using namespace std;

int main()
    int n, m, x;  cin>>n>>m>>x;
    int res = 0;
    for(int i = 1; i <= n; i++)
        int t;  cin>>t;  res += (t>=x);
    
    for(int i = 1; i <= m; i++)
        int t;  cin>>t;  res += (t<=x);
    
    cout<<res<<"\\n";
    return 0;

B.JB Loves Comma

题意:

  • 给你一个字符串s,让你在每个cjb子串的后面添加一个逗号后输出。

思路:

  • 直接扫一遍, 在每个cjb后面输出,即可。
#include<bits/stdc++.h>
using namespace std;

int main()
    string s;  cin>>s;
    cout<<s[0]<<s[1];
    for(int i = 2; i < s.size(); i++)
        cout<<s[i];
        if(s[i]=='b' && s[i-1]=='j' && s[i-2]=='c')cout<<',';
    
    return 0;


A.JB Loves Math

题意:

  • 给出两个整数a和b,然后你应该选择一个正奇数 x 和一个正偶数 y(不能更改x和y的值)。
  • 你可以在一次操作中让 a 加 x 或让 a 减 y。求将 a 更改为 b 所需的最少操作数。

思路:

  • 题目等价于让a变成b,可以增加奇数,或者减少偶数。显然次数不超过三次,分类讨论即可。
  • a小于b
    (b-a)为奇数,那么1次
    (b-a)/2为偶数,那么2次(b-a)/2
    (b-a)/2为奇数,那么3次。
  • a大于b
    (a-b)为偶数,那么1次
    (a-b)为奇数,那么2次。增加一,再减去(a-b+1)
#include<bits/stdc++.h>
using namespace std;

int main()
    int T;  cin>>T;
    while(T--)
        int a, b;  cin>>a>>b;
        if(a==b)cout<<"0\\n";
        else if(a<b)
            int t = b-a;
            if(t%2==1)cout<<"1\\n";
            else if(t/2%2==1)cout<<"2\\n";
            else cout<<"3\\n";  //1,2,3
        else
            int t = a-b;
            if(t%2==0)cout<<"1\\n";
            else cout<<"2\\n";
        
    
    return 0;

L.Candy Machine

题意:

  • 给出n个整数(1e9),从中选出若干个,满足这些数中严格大于它们的平均值的数的个数最多。
  • 求最多能选出多少个整数。

思路:

  • 假设最终选择的集合的平均数不超过k,为使平均数不超过 k,应将 ≤ k 的数全部选入,然后贪心选择 > k 的部分中最小的若干个数。
  • 因此将 N 个数从小到大排序后,最优解一定是一个前缀。
  • 枚举每个前缀,二分统计严格大于平均数的数字个数。时间复杂度nlogn。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
int a[N];

int main()
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int n;  cin>>n;
    for(int i = 1; i <= n; i++)cin>>a[i];
    sort(a+1,a+n+1);
    int res = 0;
    double pre = 0, avg;
    for(int i = 1; i <= n; i++)
        pre += a[i];
        avg = pre/i;
        int l = 0, r = i;
        while(l < r)
            int mid = l+r+1>>1;
            if(a[mid]<=avg*1.0)l = mid;
            else r = mid-1;
        
        res = max(res, i-r);
    
    cout<<res<<"\\n";
    return 0;


G.Easy Glide

题意:

  • 给定二维平面上 n 个(1000)滑行点。已知行走速度为V1,每次经过某个滑行点后可以按V2速度滑行 3 秒。
  • 求从 起点S 滑行到 终点T 所需的最少时间。

思路:

  • 建立一张 n + 2 个点的有向图,分别表示 n 个滑行点以及起点 S 和终点 T。
  • 由起点向每个点连单向边,边权为 S 按 V1 走到至该点所需的时间。
  • 由每个滑行点向其它滑行点以及终点连单向边,边权为先按V2 滑行至多 3 秒然后按 V1 行走至目的地所需的时间。
  • 朴素 Dijkstra 求 S 到 T 的最短路。
  • 复杂度O(n^2)
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int>PII;
#define x first
#define y second
const int N = 1010;

int n, v1, v2;
PII a[N];
double e[N][N];

double get_dist(PII x, PII y) return hypot(x.x-y.x, x.y-y.y)/v1; ;
double get_dist2(PII x, PII y)
    double d1 = hypot(x.x-y.x, x.y-y.y);
    return d1<=v2*3? d1/v2 : 3+(d1-v2*3)/v1;


double dist[N];
int vis[N];
double dijkstra()
    memset(dist, 0x42, sizeof dist);
    dist[0] = 0;
    for(int i = 1; i <= n; i++)
        int t = -1;
        for(int j = 0; j <= n; j++)
            if(!vis[j] && (t==-1 || dist[t]>dist[j]))t = j;
        
        vis[t] = 1;
        for(int j = 1; j <= n; j++)
            dist[j] = min(dist[j], dist[t]+e[t][j]);
        
    
    return dist[n];


void solve()
    cin>>n;
    for(int i = 1; i <= n; i++)cin>>a[i].x>>a[i].y;
    n++;
    cin>>a[0].x>>a[0].y>>a[n].x>>a[n].y;
    cin>>v1>>v2;
    memset(e, 0x42, sizeof(e));
    for(int i = 1; i <= n; i++)
        e[0][i] = get_dist(a[0], a[i]);
    
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            if(i==j)continue;
            e[i][j] = get_dist2(a[i], a[j]);
        
    
    cout<<fixed << setprecision(12) << dijkstra()<<"\\n";


int main()
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int T = 1;  //cin>>T;
    while(T--)
        solve();
    
    return 0;

M.BpbBppbpBB

题意:

  • 给定使用两种印章无重叠可旋转地打印出的字符画,统计每种印章的使用次数。

思路:

题解做法:

  • C型的黑格子数为146,S型的黑格子数为100。
  • 假设两种印章分别使用了 x 个和 y 个。
    则黑格子数为146 x + 100 y, 洞数为2 x + y, 联立解方程即可。
  • 考虑如何统计洞数,从上往下、从左往右扫一遍字符矩阵,遇到白格子时做一遍DFS,统计每个连通块中白格子的个数,若为12,检查该白格子的附近是否满足洞的特征。
  • 更方便的做法,直接找出所有的洞的个数。对于两个洞,如果中间相差的距离为7,那么就是C型(因为S拼起来肯定是>7的),那么剩下的就是S啦。
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;

int n, m; 
char a[N][N];

int dx[] = 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3;
int dy[] = 0, 1, -1, 0, 1, 2, -1, 0, 1, 2, 0, 1;
int check(int x, int y)
    if(x-1 < 1 || x+4 > n || y-2 < 1 || y+3 > m)return 0;
    for(int i = 0; i < 12; i++)
        int nx = x+dx[i], ny = y+dy[i];
        if(a[nx][ny] != '.')return 0;
    
    int res = 0;
    for(int i = x-1; i <= x+4; i++)
        for(int j = y-2; j <= y+3; j++)
            if(a[i][j]=='.')res++;
        
    
    return res==12;


void solve()
    cin>>n>>m;
    for(int i = 1; i <= n; i++)cin>>a[i]+1;
    //找出所有洞
    vector<pair<int,int>>vc;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            if(a[i][j] == '.')
                if(check(i,j))
                    vc.push_back(i,j);
                
            
        
    
    //两两判断哪些是C
    int res = 0;
    for(int i = 0; i < vc.size(); i++)
        for(int j = i+1; j < vc.size(); j++)
            int x1 = vc[i].first, y1 = vc[i].second;
            int x2 = vc[j].first, y2 = vc[j].second;
            if((abs(x1-x2)==7 && y1 == y2) || (abs(y1-y2) == 7 && x1 == x2))res++;
        
    
    cout<<res<<" "<<((int)vc.size()-2*res)<<"\\n";


int main()
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int T = 1;  //cin>>T;
    while(T--)
        solve();
    
    return 0;

I.Barbecue

题意:

  • 给定一个长度为 n 的字符串 S,q 次询问,每次询问指定 S 的一个子串,两个人在该子串上进行博弈。
  • 博弈双方轮流删去当前串开头或结尾的一个字符,碰到回文串的人输。
    预测两人都按最优策略操作时最终谁会获胜。
  • n, q < 1e6

思路:

  • 首先通过 Hash 或马拉车 等方式 O(1) 特判起始串为回文串的情况。
  • 对于接下来任意一个局面,先手操作前一定不是回文串。若先手无法进行任何操作,则说明无论删去开头还是结尾都会得到回文串。
  • 容易发现满足条件的串只能形如 ab, abab, ababab, . . .这说明终止态的长度一定是偶数,因此输赢只和起始串长度的奇偶性有关。
  • 时间复杂度 O(n + q)。
//马拉车
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int n,q,l,r;
string s;

int main()
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int n,q;
    string s;
    cin>>n>>q>>s;
    vector<int> d1(n);
    for(int i = 0, l = 0,r = -1; i < n; i++)
        int k = (i > r) ? 1 : min(d1[l + r - i],r - i + 1);
        while(0 <= i - k && i + k < n && s[i - k] == s[i + k]) k++;
        d1[i] = k--;
        if(i + k > r)
            l = i - k;
            r = i + k;
        
    
    while(q--)
        cin>>l>>r;
        l--,r--;
        int mid = (l + r)/2;
        以上是关于ZJCPC2022 第19届 浙江省赛The 19th Zhejiang Provincial Collegiate Programming Contest(CBALGMIF 8题)的主要内容,如果未能解决你的问题,请参考以下文章

ZJCPC2018 第15届 浙江省赛The 15th Zhejiang Provincial Collegiate Programming Contest(MABLJK 6题)

ZJCPC2018 第15届 浙江省赛The 15th Zhejiang Provincial Collegiate Programming Contest(MABLJK 6题)

ZJCPC2020 第17届 浙江省赛The 17th Zhejiang Provincial Collegiate Programming Contest(ABCIK 5题)

ZJCPC2019 第16届 浙江省赛The 16th Zhejiang Provincial Collegiate Programming Contest(GFHIJ 5题)

ZJCPC2019 第16届 浙江省赛The 16th Zhejiang Provincial Collegiate Programming Contest(GFHIJ 5题)

ZJCPC2021 第18届 浙江省赛The 18th Zhejiang Provincial Collegiate Programming Contest(ACFGJLM 7题)