Codeforces Round #621 (Div. 1 + Div. 2)(A~D)

A. Cow and Haybales

分析

水题直接代码。。

代码

#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <list>
#include <queue>
#include <deque>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
#define ios ios::sync_with_stdio(false); 
#define endl '\n'
#define PI acos(-1)
#define PB push_back
#define ll long long
#define db double
#define INF 0x3f3f3f3f
#define mod 998244353
#define lowbit(abcd) (abcd & (-abcd))

const int mxn = 2e5 + 10;
int ar[mxn];

int main()
{
    /* fre(); */
    int T;
    scanf("%d", &T);
    while(T --)
    {
        int n, d;
        scanf("%d %d", &n, &d);
        for(int i = 0; i < n; i ++)
            scanf("%d", &ar[i]);
        int ct = ar[0];
        for(int i = 1; i < n && d > 0; i ++)
        {
            int t = (d / i);
            int c = min(t, ar[i]);
            ct += c;
            d -= c * i;
        }
        printf("%d\n", ct);
    }

    return 0;
}

B. Cow and Friend

分析

  • 题意
  1. 给我我们n个兔子喜欢的数字,每次兔子🐰可以沿着任意的方向跳一段距离,这个距离为兔子喜欢的数字,现在兔子想从(0,0)到(s,0)问兔子最少需要跳多少次??
  • 思路
  1. 每次兔子都以最大距离沿着x轴方向跳,如果最大跳跃距离正好是s的倍数的话直接跳就行了,否则跳到最后,剩下的最后一段距离小于当前兔子的最大跳跃距离的话,我们要对这个情况进行分类讨论,设之前兔子已经跳了t步,如果t>=1那么可以让兔子之前的t步稍微条约的时候有点向上的倾斜角度,给最后一段腾出一段距离,是最后一次恰好可以跳到终点,这个时候答案就是t+1,如果t = 0的话,我们至少需要两步来跳一个等腰三角形,从而到达目的地,此时答案为 2

代码1

#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <list>
#include <queue>
#include <deque>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
#define ios ios::sync_with_stdio(false) 
#define endl '\n'
#define PI acos(-1)
#define PB push_back
#define ll long long
#define db double
#define INF 0x3f3f3f3f
#define mod 998244353
#define lowbit(abcd) (abcd & (-abcd))

const int mxn = 2e5 + 10;
int ar[mxn];


int main()
{
    /* fre(); */
    int t;
    scanf("%d", &t);
    while(t --)
    {
        int n, s;
        scanf("%d %d", &n, &s);
        int mx= 0;
        int ans = 0;
        for(int i = 1; i <= n; i ++)
        {
            scanf("%d", &ar[i]);
            mx = max(mx, ar[i]);
            if(ar[i] == s)
                ans = 1;
        }

        if(ans)
        {
            printf("%d\n", ans);
            continue;
        }

        if(s % mx == 0)
        {
            ans = s / mx;
        }
        else
        {
            ans = s / mx + 1;
        }
        printf("%d\n", max(2, ans));    
    }

    return 0;
}

代码2

#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <list>
#include <queue>
#include <deque>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
#define ios ios::sync_with_stdio(false); 
#define endl '\n'
#define PI acos(-1)
#define PB push_back
#define ll long long
#define db double
#define INF 0x3f3f3f3f
#define mod 998244353
#define lowbit(abcd) (abcd & (-abcd))

const int mxn = 2e5 + 10;
int ar[mxn];
map<int,int> mp;

int main()
{
    /* fre(); */
    int T;
    scanf("%d", &T);
    while(T --)
    {
        mp.clear();
        int n, d;
        scanf("%d %d", &n, &d);
        for(int i = 1; i <= n; i ++)
            scanf("%d", &ar[i]), mp[ar[i]] ++;

        int ans = INF;
        for(int i = 1; i <= n; i ++)
        {

            int mx = ar[i];
            int D = d;

            int t = D / mx;
            D -= t * mx;
            if(D)
            {
                if(mp[D])
                    t += 1;
                else
                {
                    if(t >= 1)
                        t += 1;
                    else
                        t += 2;
                }
            }
            /* printf("%d = %d %d\n", i, t, D); */
            ans = min(ans, t);
        }

        printf("%d\n", ans);
    }

    return 0;
}


C. Cow and Message

分析

  • 题意
    注意在👇我们说的“等差子序列”都是指的是在长度相同的情况下,某个相同子序列(并不是指的所有长度相同的子序列)
  1. 给我们一个长度为n的字符串s,问s的所有成等差序列的子序列中,出现次数最多的那个等差子序列出现的次数是多少次?
  • 思路
  1. 首先明白在s的所有子串中,我们只需要讨论 长度为1的子序列、长度为2的子这两种情况(而且这两种情况的子序列本身有长度的关系已经是成等差序列了),对于长度大于2的成等差序列的子串我们都可以是为是在长度2的等差子序列的基础上加上另外一个字符形成的的,所以长度大于2的等差子序列出现的次数一定小于等于长度为2的等差子序列的长度为
  2. 为什么还要单独讨论长度为1的等差子序列呢?仅仅讨论长度为2的等差子序列不行吗?,,,,不行,因为长度为1的子序列可能比长度为2的子序列出现的次数还多(如 lol)

代码

#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <list>
#include <queue>
#include <deque>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
#define ios ios::sync_with_stdio(false) 
#define endl '\n'
#define PI acos(-1)
#define PB push_back
#define ll long long
#define db double
#define INF 0x3f3f3f3f
#define mod 998244353
#define lowbit(abcd) (abcd & (-abcd))

const int mxn = 2e5 + 10;
ll dp1[mxn];            //统计单个字符出现的次数
ll dp2[30][30];         //统计仅有2个字符组成的子串的数量

int main()
{
    ios;
    /* fre(); */
    string s;
    cin >> s;
    for(int i = 0; i < s.size(); i ++)
    {
        int ch = s[i] - 'a';
        for(int j = 0; j < 26; j ++)
        {
            dp2[j][ch] += dp1[j];
        }
        dp1[ch] ++;
    }

    ll ans = 0;
    for(int i = 0; i < 26; i ++) ans = max(ans, dp1[i]);

    for(int i = 0; i < 26; i ++)
        for(int j = 0; j < 26; j ++)
            ans = max(ans, dp2[i][j]);
    printf("%lld\n", ans);

    return 0;
}

D. Cow and Fields(两遍spfa+枚举两个特殊点建立边)

分析

  • 题意
  1. 给我们一个n个点,m条边的无向图,先给我们k个点,让我们在这个k个点之间选择一对进行 建一条边,问过建立了这条边,我们能够使从1到n的最短路距离的最大值可变为多少(我们建立的这条边,可能是最短路距离减小,而我们要做的就是合理的建边,使最短路距离尽可能的减少,这样最短路距离就尽可能的大了)?
  • 思路
  1. 跑两遍 spfa,第一计算起点1到其他点x到距离dis1[x];第二遍计算n到其他点y的距离dis2[y]
  2. 接下的核心思想就是枚举k中的任意两个点x,y,这时从1到n经过x,y两点有两条路可以走,第一条:1-x-y-n,第二条:1-y-x-n,我们选择两条路线距离较小的那么个距离 d=min(dis1[x]+1+dis2[y],  dis1[y]+1+dis2[x])d =min(dis1[x]+1+dis2[y],~~dis1[y]+1+dis2[x]),这样由于我们枚举的x,y的值不同,那么得到的d的值也不同,在所有的d的取值中我们取最大的那个d, 之后题目的答案就是minddis1[n]min(d,dis1[n])
  3. 注意 3. 说的是核心思想是没问题的,但是我不可能暴力枚举x、y的值的(n<2e5),所以要要优化这个暴力枚举的过程,把不可能产生答案的枚举删除掉就行了,而优化的思想是:要想使最短路距离尽可能的大,我们要建立边的两个节点x、y之间的距离应该应该包含尽量少的边,这样我们人为建立的边替代的边就替代边数少了,这样最短路径就可能更长了,,,具体实现看代码

另外一种优化的枚举x、y过程的思路,传送门

优化1代码

#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <list>
#include <queue>
#include <deque>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
#define ios ios::sync_with_stdio(false) 
#define endl '\n'
#define PI acos(-1)
#define PB push_back
#define ll long long
#define db double
#define INF 0x3f3f3f3f
#define mod 998244353
#define lowbit(abcd) (abcd & (-abcd))

const int mxn = 2e5 + 10;
vector<int> V;
vector<int> edge[mxn];
int q[mxn * 10];
int dis1[mxn], dis2[mxn];       //dis1 表示从起点1到其他各点的最短路,dis2表示从n到其他的点的最短路

void bfs(int dis[], int s)
{
    int qh = 0, qt = 0;
    fill(dis, dis + mxn, INF);
    q[++ qt] = s;
    dis[s] = 0;
    while(qt > qh)
    {
        s = q[++ qh];
        for(auto x : edge[s])
        {
            if(dis[x] == INF)
            {
                dis[x] = dis[s] + 1;
                q[++ qt] = x; 
            }
        }
    }
}

int main()
{
    /* fre(); */
    int n, m, k;
    scanf("%d %d %d", &n, &m, &k);
    int p;
    for(int i = 0; i < k; i ++)
        scanf("%d", &p), V.push_back(p);
    int u, v;
    for(int i = 0; i < m; i ++) 
    {
        scanf("%d %d", &u, &v);
        edge[u].push_back(v);
        edge[v].push_back(u);
    }
    bfs(dis1, 1);
    bfs(dis2, n);

    vector<pair<int, int> > vec;
    for(auto x : V)
         vec.push_back(make_pair( dis1[x], x ));
    sort(vec.begin(), vec.end());
    
    int ans = 0;
    for(int i = 1; i < vec.size(); i ++)
    {
        int d = dis1[n];
        int u = vec[i - 1].second, v = vec[i].second;
        d = min(d, dis1[u] + dis2[v] + 1);
        d = min(d, dis1[v] + dis2[u] + 1);
        ans = max(ans, d);
    }
    printf("%d\n", ans);

    return 0;
}


优化2代码


#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <list>
#include <queue>
#include <deque>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
#define ios ios::sync_with_stdio(false) 
#define endl '\n'
#define PI acos(-1)
#define PB push_back
#define ll long long
#define db double
#define INF 0x3f3f3f3f
#define mod 998244353
#define lowbit(abcd) (abcd & (-abcd))

const int mxn = 2e5 + 10;
vector<int> V;
vector<int> edge[mxn];
int q[mxn * 10];
int dis1[mxn], dis2[mxn];       //dis1 表示从起点1到其他各点的最短路,dis2表示从n到其他的点的最短路

void bfs(int dis[], int s)
{
    int qh = 0, qt = 0;
    fill(dis, dis + mxn, INF);
    q[++ qt] = s;
    dis[s] = 0;
    while(qt > qh)
    {
        s = q[++ qh];
        for(auto x : edge[s])
        {
            if(dis[x] == INF)
            {
                dis[x] = dis[s] + 1;
                q[++ qt] = x; 
            }
        }
    }
}

int main()
{
    /* fre(); */
    int n, m, k;
    scanf("%d %d %d", &n, &m, &k);
    int p;
    for(int i = 0; i < k; i ++)
        scanf("%d", &p), V.push_back(p);
    int u, v;
    for(int i = 0; i < m; i ++) 
    {
        scanf("%d %d", &u, &v);
        edge[u].push_back(v);
        edge[v].push_back(u);
    }
    bfs(dis1, 1);
    bfs(dis2, n);

    vector<pair<int, int> > vec;
    for(auto x : V)
         vec.push_back(make_pair( dis1[x] - dis2[x], x ));
    sort(vec.begin(), vec.end());
    
    int mx = -INF, bs = 0;
    for(auto x : vec)
    {
        bs = max(bs, dis2[x.second] + mx);
        mx = max(mx, dis1[x.second]);
    }

    printf("%d\n", min(dis1[n], bs + 1));

    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章