1. 程式人生 > >【AtCoder】AGC011

【AtCoder】AGC011

friend amp add 二分圖 ear length red 循環 code

AGC011

A - Airport Bus

大意:有N個人,每個人只能在\([T_i,T_i +K]\)這段區間乘車,每輛車安排C人,問最少安排幾輛車

直接掃,遇到一個沒有車的在\(T_i +K\)分配一輛

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <cmath>
#include <bitset>
#include <queue>
#define enter putchar('\n')
#define space putchar(' ')
//#define ivorysi
#define pb push_back
#define mo 974711
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define MAXN 500005
#define eps 1e-12
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < '0' || c > '9') {
    if(c == '-') f = -1;
    c = getchar();
    }
    while(c >= '0' && c <= '9') {
    res = res * 10 - '0' + c;
    c = getchar();
    }
    res = res * f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) out(x / 10);
    putchar('0' + x % 10);
}
int N,C,K;
int T[1000005];
void Solve() {
    read(N);read(C);read(K);
    for(int i = 1 ; i <= N ; ++i) read(T[i]);
    sort(T + 1,T + N + 1);
    int ans = 0;
    int cnt = 0,t = 0;
    for(int i = 1 ; i <= N ; ++i) {
    if(t < T[i] || !cnt) {
        ++ans;
        t = T[i] + K;
        cnt = C;
    }
    --cnt;
    }
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

B - Colorful Creatures

大意:N個怪獸顏色兩兩不同,兩個怪物如果一個大小是A顏色是B,一個大小是C(C <= 2 * A)顏色是D,新怪物可以是大小A+C,顏色是B,問最後可能是幾種顏色

直接二分找滿足要求的數的位置,然後能擴到的最大體積就是從最小的數到這個數的前綴和,每次至少擴大兩倍,所以只用log次

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <cmath>
#include <bitset>
#include <queue>
#define enter putchar('\n')
#define space putchar(' ')
//#define ivorysi
#define pb push_back
#define mo 974711
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define MAXN 500005
#define eps 1e-12
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < '0' || c > '9') {
    if(c == '-') f = -1;
    c = getchar();
    }
    while(c >= '0' && c <= '9') {
    res = res * 10 - '0' + c;
    c = getchar();
    }
    res = res * f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) out(x / 10);
    putchar('0' + x % 10);
}
int N;
int64 A[100005],tmp[100005],sum[1000005];
void Solve() {
    read(N);
    for(int i = 1 ; i <= N ; ++i) {
    read(A[i]);
    tmp[i] = A[i];
    }
    tmp[N + 1] = 1000000001;
    sort(tmp + 1,tmp + N + 2);
    int ans = 0;
    for(int i = 1 ; i <= N ; ++i) {
    sum[i] = sum[i - 1] + tmp[i]; 
    }
    for(int i = 1 ; i <= N ; ++i) {
    if(2 * A[i] >= tmp[N]) {++ans;continue;}
    int t = lower_bound(tmp + 1,tmp + N + 2,2 * A[i] + 1) - tmp - 1;
    while(1) {
        if(2 * sum[t] >= tmp[N]) {++ans;break;}
        int p = lower_bound(tmp + 1,tmp + N + 2,sum[t] * 2 + 1) - tmp - 1;
        if(p == t) break;
        t = p;
    }
    }
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

C - Squared Graph

大意是給出一張圖,然後建一張新圖,新圖的點標號是(a,b)
如果a和c有一條邊,b和d有一條邊,那麽(a,b)和(c,d)之間有一條邊

我們把這道題當成這道題來做,給出兩張圖,如果第一張圖有邊(a,c),第二張圖有邊(b,d),那麽第三張圖上有邊(a,b)(c,d)

如果某張圖只有一個點,那麽答案就是另一張圖的點數

然後我們發現對於某兩個點對第一張圖(a,c),第二張圖(b,d)如果有一條長度為L的路徑,那麽第三張圖(a,b)(c,d)一定可以聯通
但是我們發現我們經過的路徑可以不是簡單路徑,也就是我們反復走一條邊,那麽我們只和路徑長度的奇偶性有關了

很容易想到二分圖,如果兩張圖都是二分圖且聯通的話,那麽第三張圖聯通分量的個數是2

分別是\(S_a * T_b \cup T_a * S_b\)\(S_a * S_b \cup T_a * T_b\)

而兩張圖都是非二分圖且聯通的話,任意路徑的奇偶性都可以互相轉化,所以整張圖就是一個聯通塊
那麽我們求出兩個圖的孤立點個數\(i_A,i_B\),兩個圖的非二分圖聯通塊個數\(p_A,p_B\),兩個圖的二分圖聯通塊個數\(q_A,q_B\)
答案就是
\(i_Ai_B + i_A(N_B - i_B) + i_B(N_A - i_A) + p_Ap_B + p_Aq_B + p_Bq_A + 2q_Aq_B\)

代碼

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <cmath>
#include <bitset>
#include <queue>
#define enter putchar('\n')
#define space putchar(' ')
//#define ivorysi
#define pb push_back
#define mo 974711
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define MAXN 200005
#define eps 1e-12
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < '0' || c > '9') {
    if(c == '-') f = -1;
    c = getchar();
    }
    while(c >= '0' && c <= '9') {
    res = res * 10 - '0' + c;
    c = getchar();
    }
    res = res * f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) out(x / 10);
    putchar('0' + x % 10);
}
int N,M,I,P,Q;
struct node {
    int next,to;
}E[MAXN * 2];
int head[MAXN],sumE,col[MAXN];
bool vis[MAXN];
void dfs(int u) {
    vis[u] = 1;
    for(int i = head[u] ; i ; i = E[i].next) {
    int v = E[i].to;
    if(!vis[v]) {
        dfs(v);
    }
    }
}
bool paint(int u) {
    if(!col[u]) col[u] = 2;
    for(int i = head[u] ; i; i = E[i].next) {
    int v = E[i].to;
    if(!col[v]) {col[v] = col[u] ^ 1;if(!paint(v)) return false;}
    else if(col[v] == col[u]) return false;
    }
    return true;
}
void add(int u,int v) {
    E[++sumE].to = v;
    E[sumE].next = head[u];
    head[u] = sumE;
}
void Solve() {
    read(N);read(M);
    int u,v;
    for(int i = 1 ; i <= M ; ++i) {
    read(u);read(v);
    add(u,v);add(v,u);
    }
    for(int i = 1 ; i <= N ; ++i) {
    if(!head[i]) ++I;
    else if(!vis[i]){
        dfs(i);
        if(paint(i)) ++Q;
        else ++P;
    }
    }
    int64 ans = 1LL * I * I + 2LL * I * (N - I);
    ans += 1LL * P * P + 2LL * P * Q + 2LL * Q * Q;
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

D - Half Reflector

大意是n個管子排成一排,每個管子有兩種狀態,A狀態是從某個方向進去,從原方向出來,B狀態是從某個方向進去,從另一個方向出來
球經過一個A狀態的管子這個管子會立刻變成B狀態,經過一個B狀態的管子會立刻變成A狀態

往裏面扔K個球,問最後管子的狀態

我們發現如果第一個管子是A的話,球會立刻彈出去

否則的話
如果第二個管子是B
那麽
A -> B
A A ->
如果第二個管子是A
A -> A
A <- B
B -> B
B A ->
也就是,每次操作後的狀態只與右邊第一個管子有關,並且最後一個管子一定是A
那麽操作可以考慮成,刪掉第一個字符,後面的字符全部取反,然後再最後填上一個A

然而有K次,我們發現起點移動N次之後就是循環了
如果N次之後是
BABABA...那麽這個形態不會變

如果N次之後是
ABABAB...

那麽之後的形態就是
BBABAB...
ABABAB...
這樣的循環了

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <cmath>
#include <bitset>
#include <queue>
#define enter putchar('\n')
#define space putchar(' ')
//#define ivorysi
#define pb push_back
#define mo 974711
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define MAXN 200005
#define eps 1e-12
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < '0' || c > '9') {
    if(c == '-') f = -1;
    c = getchar();
    }
    while(c >= '0' && c <= '9') {
    res = res * 10 - '0' + c;
    c = getchar();
    }
    res = res * f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) out(x / 10);
    putchar('0' + x % 10);
}
char s[MAXN];
int N,K,p = 1,num[MAXN],cnt,st;
void Solve() {
    read(N);read(K);
    scanf("%s",s + 1);
    for(int i = 1 ; i <= N ; ++i) num[i] = s[i] - 'A';
    st = num[1];
    while(K--) {
    if(st == 0) {st ^= 1;num[p] ^= 1;}
    else {
        ++p;++cnt;
        st = num[p];
        st ^= (cnt & 1);
    }
    if(p > N) break;
    }
    if(p <= N) {
    for(int i = p ; i <= N ; ++i) putchar('A' + (num[i] ^ (cnt & 1)));
    int t = N - (N - p + 1),c = (cnt - 1) & 1;
    while(t--) {
        putchar('A' + c);
        c ^= 1;
    }
    }
    else {
    if((cnt - 1) & 1) {
        for(int i = 1 ; i <= N ; ++i) putchar('A' + (i & 1));
    }
    else {
        putchar('A' + (K & 1));
        for(int i = 1 ; i < N ; ++i) putchar('A' + (i & 1));
    }
    }
    enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

E - Increasing Numbers

我們發現一個非下降的數字一定可以用不超過九個1111111111...1111表示

那麽我們可以得到這樣的一個式子,假如我們用了k個數,那麽最多的話可以是這樣的
\(N = \sum_{i = 1}^{9k} (10^{r_i} - 1) / 9\)
\(9N + 9k = \sum_{i = 1}^{9k} 10^{r_{i}}\)

我們只要每次計算出9N + 9 ,9N + 18...,然後看看十進制下每一位的數字和有沒有超過9k,直接加的話最壞情況是一次操作\(O(L)\)的,但是大家應該都有種直覺總的操作就是\(O(L)\)的……就是勢能分析啦,不太會證,就是一次長的進位過後之後不會再進位了。。。

復雜度\(O(lg N)\)

代碼

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <cmath>
#include <bitset>
#include <queue>
#define enter putchar('\n')
#define space putchar(' ')
//#define ivorysi
#define pb push_back
#define mo 974711
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define MAXN 200005
#define eps 1e-12
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < '0' || c > '9') {
    if(c == '-') f = -1;
    c = getchar();
    }
    while(c >= '0' && c <= '9') {
    res = res * 10 - '0' + c;
    c = getchar();
    }
    res = res * f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) out(x / 10);
    putchar('0' + x % 10);
}
struct Bignum {
    vector<int> v;
    int sum;
    Bignum operator = (string s) {
    v.clear();
    sum = 0;
    for(int i = s.length() - 1 ; i >= 0 ; --i) {
        v.pb(s[i] - '0');
        sum += s[i] - '0';
    }
    return *this;
    }
    friend Bignum operator * (const Bignum &a,const int b) {
    int s = a.v.size();
    Bignum c;c.v.clear();
    for(int i = 0 ; i <= s ; ++i) c.v.pb(0);
    int g = 0;
    for(int i = 0 ; i < s ; ++i) {
        int x = a.v[i] * b + g;
        c.v[i] = x % 10;
        g = x / 10;
    }
    if(g) c.v[s] = g;
    for(int i = s ; i > 0 ; --i) {
        if(c.v[i] == 0) c.v.pop_back();
        else break;
    }
    c.sum = 0;s = c.v.size();
    for(int i = 0 ; i < s ; ++i) c.sum += c.v[i];
    return c;
    }
}A;
string s;
void Solve() {
    cin>>s;
    A = s;
    A = A * 9;
    int ans = 0;
    while(1) {
    int s = A.v.size();
    int g = 9;
    for(int i = 0 ; i < s ; ++i) {
        if(!g) break;
        A.sum -= A.v[i];
        int x = A.v[i] + g;
        A.v[i] = x % 10;
        A.sum += A.v[i];
        g = x / 10;
    }
    if(g) A.v.pb(g),A.sum += g;
    ++ans;
    if(ans * 9 >= A.sum) break;
    }
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

【AtCoder】AGC011