Codeforces-541div2

http://www.javashuo.com/article/p-vlziaven-gk.htmlhtml

codeforces-1131A~Gios

這場不少題都很簡單,,應該是要能至少作出4道的,,可是我一道wa了懵逼一道不知道如何寫代碼實現鏈表,,又是掉分場,,QAQ,,,c++

A. Sea Battle

求兩個左對齊的矩形的外圍一圈的面積(方格數),,,一開始去想着一層一層的找規律去推公式去了,,,推到一半發現愈來愈亂,,又想了一會纔想起直接分紅兩個矩形:紅色的擴大一圈後的和去掉一層後的藍色的矩形的面積和減去原來兩個矩形的面積和就好了,,,數組

//cf
#include <bits/stdc++.h>
//#include <iostream>
//#include <cstdio>
//#include <cstdlib>
//#include <string.h>
//#include <algorithm>
#define aaa cout<<233<<endl;
#define endl '\n'
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, ull> pii;
const int inf = 0x3f3f3f3f;//1061109567
const ll linf = 0x3f3f3f3f3f3f3f;
const double eps = 1e-6;
const double pi = 3.14159265358979;
const int maxn = 2e5 + 5;
const int maxm = 2e5 + 5;
const ll mod = 1e9 + 7;

int main()
{
//    freopen("233.in" , "r" , stdin);
//    freopen("233.out" , "w" , stdout);
    ios_base::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    ll w1, w2, h1, h2;
    cin >> w1 >> h1 >> w2 >> h2;
    ll ans = (w1 + 2) * (h1 + 2) + (w2 + 2) * h2 - w1 * h1 - w2 * h2;
    cout << ans << endl;
    return 0;
}

B. Draw!

這道題的題意是給你足球比賽某個時刻的比分,而後問你可能的最大平分的狀況由幾種,,,函數

題意很簡單,,,就是我當時在作的的時候推的方法錯了,,而後wa,,由於可是思路也不清晰,,繼續想下去耽誤時間又時錯的就放棄了這道題,,(如今看來應該作完C去繼續想一下B的,,,spa

顯然爲了出現平分的狀況,對於平分x確定知足: \(a \leq x \leq c ,b \leq x \leq d\),其中(a,b),(c,d)表明相鄰的兩個時刻的比分,(a,b)出現的時刻早一些,這樣咱們就能夠推出 \(max(a,b) \leq x \leq min(c,d)\),,(我就這裏沒想出來,,當時腦殼是糊的,,,)而後介於這兩個時刻的比分之間的可能平分數就是 \(min(c,d)-max(a,b)+1 \ 當且僅當式子的值大於等於零\),,若是中間時刻出現一個比分相同的就意味着多加了一次,減掉,,對於最後的比分若是相等還要再加一個,,code

//cf
#include <bits/stdc++.h>
//#include <iostream>
//#include <cstdio>
//#include <cstdlib>
//#include <string.h>
//#include <algorithm>
#define aaa cout<<233<<endl;
#define endl '\n'
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int inf = 0x3f3f3f3f;//1061109567
const ll linf = 0x3f3f3f3f3f3f3f;
const double eps = 1e-6;
const double pi = 3.14159265358979;
const int maxn = 2e5 + 5;
const int maxm = 2e5 + 5;
const ll mod = 1e9 + 7;
int a[maxn], b[maxn];

int main()
{
//    freopen("233.in" , "r" , stdin);
//    freopen("233.out" , "w" , stdout);
    ios_base::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int n;cin >> n;
    int ans = 0, la, lb, a, b;
    la = lb = 0;
    for(int i = 1; i <= n; ++i)
    {
        cin >> a >> b;
        if(min(a, b) - max(la, lb) + 1 >= 0)
            ans += min(a, b) - max(la , lb) + 1;
        if(a == b)--ans;
        la = a;lb = b;
    }
    if(la == lb)++ans;
    cout << ans << endl;
    return 0;
}

C. Birthday

c題很簡單,就是給你一組數,而後讓那弄出一個序列,知足全部相鄰兩個數的差值的最大值最小,,htm

看樣例就知道應該輸出一箇中間高兩邊低的序列就行了,,,blog

//cf
#include <bits/stdc++.h>
//#include <iostream>
//#include <cstdio>
//#include <cstdlib>
//#include <string.h>
//#include <algorithm>
#define aaa cout<<233<<endl;
#define endl '\n'
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int inf = 0x3f3f3f3f;//1061109567
const ll linf = 0x3f3f3f3f3f3f3f;
const double eps = 1e-6;
const double pi = 3.14159265358979;
const int maxn = 2e5 + 5;
const int maxm = 2e5 + 5;
const ll mod = 1e9 + 7;
int a[maxn], b[maxn];

int main()
{
//    freopen("233.in" , "r" , stdin);
//    freopen("233.out" , "w" , stdout);
    ios_base::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 + 1 + n);
    if(n & 1)
    {
        int p = n / 2 + 1;
        for(int i = n; i >= 1; i -= 2)
            b[p--] = a[i];
        p = n / 2 + 2;
        for(int i = n - 1; i >= 1; i -= 2)
            b[p++] = a[i];
    }
    else
    {
        int p = n / 2;
        for(int i = n; i >= 1; i -= 2)
            b[p--] = a[i];
        p = n / 2 + 1;
        for(int i = n - 1; i >= 1; i -= 2)
            b[p++] = a[i];
    }
    for(int i = 1; i <= n; ++i)cout << b[i] << " ";
    cout << endl;
    return 0;
}

D. Gourmet choice

這道題在比賽的時候有人在羣裏說了一句「差分約束」,,看這個題面的確像是差分約束的題,,,後來又看到不少人用的是 並查集縮點+拓撲排序,,,(第一據說能用並查集縮點的,,之前值見過跑Tarjan縮點的,,)排序

題面的意思是兩組菜,一組是n道一組是m道,,而後給出這些菜直接的評分關係,而後讓你求出每道菜具體可能的數值是多少(要知足所給的大小關係),,輸出結果

並查集縮點+拓撲排序

首先題目要咱們求一個數列,使得這n+m個數的大小關係知足題目所給的要求,,這時咱們能夠將題目所求當作求一個最大值最小鏈,鏈中的邊(u,v)表示v所表明的值大於或等於u的值,,這樣就將問題轉化成了一個n+m的圖,,其中當s[i][j]爲'>'號時,就加一條n+j->i的邊,,而後判斷這個圖是不是DAG圖,,不是的話證實有環,,無解,,沒有環的狀況下用 拓撲排序 求圖的最長鏈,,同時標記每一個點的值應該是上一個點的加一

對於相等評分的i,j,,咱們將它們劃在同一個集合裏,,這樣用一個點表示這個集合裏的全部點,,它最後的評分和集合裏的全部點的評分同樣(縮點),,這裏的縮點過程用並查集來實現,,最後的點都映射到了新的點中

這樣咱們直接對每個用到原來1->n+m的點都求一下它所在的點集,,用並查集的 _find(x) 就好了,,,

最後遍歷一遍全部的n+m個點看所在的集合是否都被標記了,,有一個沒有的話就是無解的啦,,,

輸出的時候依次輸出前n個點所在點集的標號,而後後m個點所在點集的標號,,

//cf
#include <bits/stdc++.h>
//#include <iostream>
//#include <cstdio>
//#include <cstdlib>
//#include <string.h>
//#include <algorithm>
#define aaa cout<<233<<endl;
#define endl '\n'
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int inf = 0x3f3f3f3f;//1061109567
const ll linf = 0x3f3f3f3f3f3f3f;
const double eps = 1e-6;
const double pi = 3.14159265358979;
const int maxn = 2e5 + 5;
const int maxm = 2e5 + 5;
const ll mod = 1e9 + 7;
int a[maxn], b[maxn];
int fa[maxn];
int _find(int x)
{
    if(fa[x] == x)return x;
    return fa[x] = _find(fa[x]);
}
void _union(int x, int y)
{
    int f1 = _find(x);
    int f2 = _find(y);
    if(f1 > f2)fa[f1] = f2;
    else       fa[f2] = f1;
}
//toposort
vector<int> g[maxn];
int du[maxn], n, m, l[maxn];
int ans[maxn];      //保存全部點的編號
bool toposort(int cnt)
{
    int tot = 0;
    queue<int> q;
    for(int i = 1; i <= n + m; ++i)
        if(!du[_find(i)] && fa[i] == i)
            q.push(_find(i)), ans[_find(i)] = 1;//全部入度爲零的點的集合標記爲1
    while(!q.empty())
    {
        int x = q.front(); q.pop();
        for(int i = 0; i < g[x].size(); ++i)
        {
            int t = g[x][i];
            --du[t];
            if(!du[t])q.push(t), ans[t] = ans[x] + 1;//這條鏈上的下一個點的編號比上一個大1,,也就是知足題乾的>
        }
    }
    for(int i = 1; i <= n + m; ++i)//若是有一個點沒有被編號,即最長鏈裏沒有它就說明無解
        if(!ans[_find(i)])
            return false;
    return true;
}
char s[1005][1005];
int main()
{
//    freopen("233.in" , "r" , stdin);
//    freopen("233.out" , "w" , stdout);
//    ios_base::sync_with_stdio(0);
//    cin.tie(0);cout.tie(0);
    scanf("%d%d", &n , &m);
    for(int i = 1; i <= n; ++i)scanf("%s", s[i] + 1);
    for(int i = 1; i <= n + m; ++i)fa[i] = i;
    for(int i = 1; i <= n + m; ++i)du[i] = 0;
    int cnt = n + m;
    //用並查集縮點後判斷是否是DAG圖
    for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= m; ++j)
            if(s[i][j] == '=')
                _union(i, n + j), --cnt;
    for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= m; ++j)
        {
            if(s[i][j] == '<')
                g[_find(i)].push_back(_find(n + j)), ++du[_find(n + j)];
            if(s[i][j] == '>')
                g[_find(n + j)].push_back(_find(i)), ++du[_find(i)];
        }
    if(toposort(cnt))
    {
        printf("Yes\n");
        for(int i = 1; i <= n; ++i)
            printf("%d ", ans[_find(i)]);
        printf("\n");
        for(int j = 1; j <= m; ++j)
            printf("%d ", ans[_find(j + n)]);
        printf("\n");
    }
    else
    {
        printf("No\n");
    }

    return 0;
}

參考

差分約束

spfa跑的時候容易t,,(哪天在補這道題吧

差分約束的話直接建圖,,注意一下細節就好了,,,

//cf
#include <bits/stdc++.h>
//#include <iostream>
//#include <cstdio>
//#include <cstdlib>
//#include <string.h>
//#include <algorithm>
#define aaa cout<<233<<endl;
#define endl '\n'
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int inf = 0x3f3f3f3f;//1061109567
const ll linf = 0x3f3f3f3f3f3f3f;
const double eps = 1e-6;
const double pi = 3.14159265358979;
const int maxn = 1e6 + 5;
const int maxm = 2e5 + 5;
const ll mod = 1e9 + 7;
struct edge
{
    int v, w;
    edge(int _v, int _w):v(_v), w(_w){}
};
vector<edge> e[maxn];
void addedge(int u, int v, int w)
{
    e[u].push_back(edge(v, w));
}
bool vis[maxn];
int cnt[maxn], dis[maxn], sta[maxn];
bool spfa(int s, int n)
{
    for(int i = 0; i <= n; ++i)vis[i] = false;
    for(int i = 0; i <= n; ++i)cnt[i] = 0;
    for(int i = 0; i <= n; ++i)dis[i] = inf;
    vis[s] = true;
    cnt[s] = 1;
    dis[s] = 0;
    int top = -1;
    sta[++top] = s;
    while(~top)
    {
        int u = sta[top--];
        vis[u] = false;
        for(int i = 0; i < e[u].size(); ++i)
        {
            int v = e[u][i].v;
            int w = e[u][i].w;
            if(dis[v] > dis[u] + w)
            {
                dis[v] = dis[u] + w;
                if(!vis[v])
                {
                    vis[v] = true;
                    sta[++top] = v;
                    if(++cnt[v] > n)return false;
                }
            }
        }
    }
    return true;
}
char s[1005][1005];
int main()
{
//    freopen("233.in" , "r" , stdin);
//    freopen("233.out" , "w" , stdout);
//    ios_base::sync_with_stdio(0);
//    cin.tie(0);cout.tie(0);
    int n, m; scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i)scanf("%s", s[i] + 1);
    for(int i = 1; i <= n; ++i)
    {
        for(int j = 1; j <= m; ++j)
        {
            if(s[i][j] == '>')
                addedge(i, j + n, -1);
            else if(s[i][j] == '<')
                addedge(j + n, i, -1);
            else
            {
                addedge(i, j + n, 0);
                addedge(j + n, i, 0);
            }
        }
    }
    for(int i = 1; i <= n + m; ++i)
        addedge(0, i, 1);
    if(spfa(0, n + m))
    {
        printf("Yes\n");
        int k = *min_element(dis + 1, dis + 1 + n + m);
        for(int i = 1; i <= n; ++i)
            printf("%d ", dis[i] - k + 1);
        printf("\n");
        for(int i = 1 + n; i <= n + m; ++i)
            printf("%d ", dis[i] - k + 1);
        printf("\n");
    }
    else
        printf("No\n");
    return 0;
}

E. String Multiplication

留坑

F. Asya And Kittens

當時過這道題的人不少,,直接並查集+鏈表模擬一下就能夠了,,,

惋惜我當時不知道鏈表怎麼實現(關鍵是不知道stl的list有合併兩個鏈表的函數,,,否則就不是掉分場了QAQ

每添加一對貓,,判斷他們是否是在一個集合裏,,不在的話就把他們放在一個集合裏(並查集實現),,而後合併這兩隻喵所在的鏈表,,用 std::list.splice() 做用是:對兩個鏈表進行結合(三個重載函數) 結合後第二個鏈表清空,,, ,,記得記錄下這個鏈表的位置,,,

蔡隊用的是rope合併的,,有時間瞭解一下這玩意,,

並查集+鏈表模擬

//cf
#include <bits/stdc++.h>
//#include <iostream>
//#include <cstdio>
//#include <cstdlib>
//#include <string.h>
//#include <algorithm>
#define aaa cout<<233<<endl;
#define endl '\n'
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int inf = 0x3f3f3f3f;//1061109567
const ll linf = 0x3f3f3f3f3f3f3f;
const double eps = 1e-6;
const double pi = 3.14159265358979;
const int maxn = 2e5 + 5;
const int maxm = 2e5 + 5;
const ll mod = 1e9 + 7;
int father[maxn];
int find(int x)
{
    if(father[x] == x)return x;
    else return father[x] = find(father[x]);
}
void unionset(int x, int y)
{
    int f1 = find(x);
    int f2 = find(y);
    if(f1 != f2)father[f2] = f1;
}
list<ll> lst[maxn];
int main()
{
//    freopen("233.in" , "r" , stdin);
//    freopen("233.out" , "w" , stdout);
    ios_base::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int n; cin >> n;
    for(int i = 1; i <= n; ++i)father[i] = i, lst[i].pb(i);
    int a, b, ans;
    for(int i = 1; i <= n - 1; ++i)
    {
        cin >> a >> b;
        int pa = find(a);
        int pb = find(b);
        lst[pa].splice(lst[pa].end(), lst[pb]);
        unionset(a, b);
        ans = pa;
    }
    for(auto p : lst[ans])cout << p << " ";
    return 0;
}

並查集+rope模擬

rope是一個塊狀鏈表,,

須要在g++中使用,,同時加上特定的頭文件:

#include<ext/rope>
using namespace __gnu_cxx;

經常使用操做有:

  • pusb_back(x): 在末尾追加x
  • insert(pos, x): 在pos插入x
  • erase(pos, x): 在pos開始刪除連續x個元素
  • replace(pos, x): 從pos開始替換成x
  • substr(pos, x): 提去從pos開始的x個元素
  • at(x) or [x]: 訪問第x個元素

insert() ,substr() 和 erase()連用能夠實現對一段數據的轉移:

實現對a數組中[x, y]的數字放到最前面
a.insert(0, a.substr(x - 1, y));
a.erase(x + y - 1, y);

這道題貌似直接放在一個鏈表的後面用 "+=" ,就好了,,,(沒找到介紹重載 "+="的博客),,,

聽說這玩意的時間複雜度是 O(玄學),,emmm,,比上面那種還慢一點,,

//cf
#include <bits/stdc++.h>
//#include <iostream>
//#include <cstdio>
//#include <cstdlib>
//#include <string.h>
//#include <algorithm>
#define aaa cout<<233<<endl;
#define endl '\n'
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int inf = 0x3f3f3f3f;//1061109567
const ll linf = 0x3f3f3f3f3f3f3f;
const double eps = 1e-6;
const double pi = 3.14159265358979;
const int maxn = 1e6 + 5;
const int maxm = 2e5 + 5;
const ll mod = 1e9 + 7;
int fa[maxn];
int _find(int x)
{
    if(fa[x] == x)return x;
    return fa[x] = _find(fa[x]);
}
void _union(int x, int y)
{
    int f1 = _find(x);
    int f2 = _find(y);
    if(f1 > f2)fa[f1] = f2;
    else       fa[f2] = f1;
}
#include <ext/rope>
using namespace __gnu_cxx;
rope<int> a[maxn];
int main()
{
//    freopen("233.in" , "r" , stdin);
//    freopen("233.out" , "w" , stdout);
    ios_base::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int n;cin >> n;
    for(int i = 1; i <= n; ++i)fa[i] = i, a[i].push_back(i);
    int x, y;
    for(int i = 1; i <= n - 1; ++i)
    {
        cin >> x >> y;
        x = _find(x); y = _find(y);
        fa[y] = x;
        a[x] += a[y];
    }
    for(int i = 1; i <= n; ++i)
        if(_find(i) == i)
            for(int j = 0; j < a[i].size(); ++j)
                cout << a[i][j] << " ";
    cout << endl;
    return 0;
}

G. Most Dangerous Shark

留坑

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息