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;
}

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