【AtCoder】AGC028 (A-E)題解

A - Two Abbreviations

若是有最小答案的話這個答案必定是N和M的lcm
咱們考慮一下什麼狀況下
\(k \frac{L}{N} = h \frac{L}{M}\)\(k,g\)互質
顯然是在\(k = \frac{N}{gcd(N,M)},h = \frac{M}{gcd(N,M)}\)的時候成立node

咱們只要不斷枚舉\(k * i,h * i\)判斷兩個串裏這個位置的數是否相同便可ios

代碼

#include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define mp make_pair
    #define pb push_back
    #define enter putchar('\n')
    #define space putchar(' ')
    //#define ivorysi
    #define MAXN 100005
    typedef long long int64;
    using namespace std;
    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 + c - '0';
            c = getchar();
        }
        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);
    }
    int64 N,M;
    char S[MAXN],T[MAXN];
    int64 gcd(int64 a,int64 b) {
        return b == 0 ? a : gcd(b,a % b);
    }
    int64 lcm(int64 a,int64 b) {
        return a * b / gcd(a,b);
    }
    void Solve() {
        read(N);read(M);
        scanf("%s",S + 1);scanf("%s",T + 1);
        int64 c = lcm(N,M);
        int64 a = c / M,b = c / N;
        for(int i = 0 ; i <= N ; ++i) {
            if(i * a + 1 > N || i * b + 1 > M) break;
            if(S[i * a + 1] != T[i * b + 1]) {puts("-1");return;}
        }
        out(c);enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
        return 0;
    }

B - Removing Blocks

我計數計的挺麻煩的c++

我是對於每一段統計一下這一段會被哪些序列統計到ui

顯然對於長度爲K的一個段,除掉最靠前的一段和最靠後的一段,中間的每一個段,若是這一段被取了,那麼這個操做序列一定包含一個子序列,就是這一段兩側被提早取了,中間是K個數的任意排列spa

而後咱們對於每一個長度特殊處理最前一段和最後一段(由於他們的端點只有一個),對於中間的序列計算排列個數,而中間序列的代價總和能夠經過前綴和的前綴和快速算出來code

代碼

#include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define mp make_pair
    #define pb push_back
    #define enter putchar('\n')
    #define space putchar(' ')
    //#define ivorysi
    #define MAXN 100005
    typedef long long int64;
    using namespace std;
    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 + c - '0';
            c = getchar();
        }
        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);
    }
    const int MOD = 1000000007;
    int N,A[MAXN],fac[MAXN],invfac[MAXN],inv[MAXN],sum[MAXN],sum_of_sum[MAXN];
    int inc(int a,int b) {
        return a + b >= MOD ? a + b - MOD : a + b;
    }
    int mul(int a,int b) {
        return 1LL * a * b % MOD;
    }
    void update(int &x,int y) {
        x = inc(x,y);
    }
    int C(int n,int m) {
        if(n < m) return 0;
        return mul(fac[n],mul(invfac[m],invfac[n - m]));
    }
    void Solve() {
        read(N);
        for(int i = 1 ; i <= N ; ++i) {
            read(A[i]);
            sum[i] = inc(sum[i - 1],A[i]);
            sum_of_sum[i] = inc(sum_of_sum[i - 1],sum[i]);
        }
        inv[1] = 1;
        for(int i = 2 ; i <= N ; ++i) {
            inv[i] = mul(inv[MOD % i],MOD - MOD / i);
        }
        fac[0] = invfac[0] = 1;
        for(int i = 1 ; i <= N ; ++i) {
            fac[i] = mul(fac[i - 1],i);
            invfac[i] = mul(invfac[i - 1],inv[i]);
        }
        int ans = 0;
        for(int i = 1 ; i <= N ; ++i) {
            if(i == N) update(ans,mul(sum[N],fac[N]));
            else {
                update(ans,mul(inc(sum[i],inc(sum[N],MOD - sum[N - i])),mul(mul(fac[i],C(N,i + 1)),fac[N - i - 1])));
                if(i < N - 1) {
                    int t = inc(sum_of_sum[N - 1],MOD - sum_of_sum[i]);
                    update(t,MOD - sum_of_sum[N - i - 1]);
                    update(ans,mul(t,mul(mul(mul(2,fac[i]),C(N,i + 2)),fac[N - i - 2])));
                }
            }
        }
        out(ans);enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
        return 0;
    }

C - Min Cost Cycle

顯然若是最優的話,答案至少爲這2×N個數裏前N小的數的和
咱們把全部前N小的數標出來,稱爲1,後N個數稱爲0
那麼一個點有4種狀況 01 10 00 11
後兩種個數相同element

若是咱們有00(咱們必定會有相同個數的11)的話,那麼必定可行,爲何,由於咱們把01首尾相接成一個01,把10首尾相接成一個10,而後01 00 10 11就能夠了rem

若是咱們只有10或只有01,也必定可行get

惟一取不到這個解的是有10,而且有01,並且不存在00
那麼這個時候咱們枚舉兩個1相撞時1的值(若是這個1和另外一個1相撞的時候它不是最小值也不要緊,最後會被更新掉),同時計算一下兩個0相撞時0能取到的最大值,能夠用一個set維護,由於咱們須要刪掉枚舉的1所帶的那個0,除了它所在的類型只有1個的狀況string

代碼

#include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define mp make_pair
    #define pb push_back
    #define enter putchar('\n')
    #define space putchar(' ')
    //#define ivorysi
    #define MAXN 100005
    typedef long long int64;
    using namespace std;
    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 + c - '0';
            c = getchar();
        }
        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 p[MAXN][2],sum,ans,t3;
    int L[MAXN],R[MAXN],tot,ty[MAXN],cnt[10];
    pii pos[MAXN * 2];
    multiset<int64> S;
    bool cmp(pii a,pii b) {
        return p[a.fi][a.se] < p[b.fi][b.se];
    }
    void Solve() {
        read(N);
        for(int i = 1 ; i <= N ; ++i) {
            read(p[i][1]);read(p[i][0]);
            ans += p[i][1] + p[i][0];
            pos[++tot] = mp(i,0);
            pos[++tot] = mp(i,1);
        }
        sort(pos + 1,pos + tot + 1,cmp);
        for(int i = 1 ; i <= tot / 2 ; ++i) {
            sum += p[pos[i].fi][pos[i].se];
            if(!pos[i].se) L[pos[i].fi] = 1;
            else R[pos[i].fi] = 1;
            S.insert(p[pos[i].fi][pos[i].se]);
        }
        for(int i = 1 ; i <= N ; ++i) {
            if(L[i] && !R[i]) {ty[i] = 1;cnt[1]++;}
            if(!L[i] && R[i]) {ty[i] = 2;cnt[2]++;}
            if(!L[i] && !R[i]) {ty[i] = 3;cnt[3]++;}
            if(L[i] && R[i]) {ty[i] = 4;cnt[4]++;}
        }
        if(!cnt[1] || !cnt[2] || cnt[3]) {out(sum);enter;return;}
        for(int i = tot / 2 + 1 ; i <= tot ; ++i) {
            int u = pos[i].fi;
            if(cnt[ty[u]] != 1) {
                S.erase(S.find(p[u][pos[i].se ^ 1]));
                ans = min(ans,sum + p[pos[i].fi][pos[i].se] - *(--S.end()));
                S.insert(p[u][pos[i].se ^ 1]);
            }
            else ans = min(ans,sum + p[pos[i].fi][pos[i].se] - *(--S.end()));
        }
        out(ans);enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
        return 0;
    }

D - Chords

這題看起來很繁瑣,可是實際上邏輯很簡單

\(dp[i][j]\)表示一個聯通塊標記爲\(i\)爲最小的標號,\(j\)爲最大的標號,這樣的方案有多少個

首先要知足初始的時候\(i,j\)之間的點沒有連到外部的點

而後計算方案是\(g(x)\)
x是\(i,j\)之間沒有匹配的點的個數,\(g(x) = 1*3*5...(x - 3)(x - 1)\)

而後再減掉不合法的方案

\(dp[i][j] -= dp[i][k] * g(z)\)z是\(k + 1,j\)中沒有匹配過的點

最後輸出的時候還要乘上一個\(g(y)\)y表示全部除了\(i,j\)以外未匹配的點

代碼

#include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #define enter putchar('\n')
    #define space putchar(' ')
    #define fi first
    #define se second
    #define mp make_pair
    #define MAXN 200005
    //#define ivorysi
    #define pii pair<int,int>
    using namespace std;
    typedef long long int64;
    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 + c - '0';
        c = getchar();
        }
        res *= f;
    }
     
    template<class T>
    void out(T x) {
        if(x < 0) {putchar('-');x = -x;}
        if(x >= 10) out(x / 10);
        putchar('0' + x % 10);
    }
    const int MOD = 1000000007;
    int N,K;
    int A[305],B[305];
    int cnt[605][605],dp[605][605],g[605];
    bool vis[605][605];
    bool in(int a,int l,int r) {
        return a >= l && a <= r;
    }
    int inc(int a,int b) {
        return a + b >= MOD ? a + b - MOD : a + b;
    }
    int mul(int a,int b) {
        return 1LL * a * b % MOD;
    }
    void Solve() {
        read(N);read(K);
        for(int i = 1 ; i <= K ; ++i) {
        read(A[i]);read(B[i]);
        }
        g[0] = 1;
        for(int i = 1 ; i <= 2 * N ; ++i) {
        if(i & 1) g[i] = 0;
        else g[i] = mul(g[i - 2],i - 1);
        }
        for(int i = 1 ; i <= 2 * N ; ++i) {
        for(int j = i + 1 ; j <= 2 * N ; ++j) {
            for(int h = 1 ; h <= K ; ++h) {
            if(in(A[h],i,j) && in(B[h],i,j)) {
                ++cnt[i][j];
            }
            else if((!in(A[h],i,j) && in(B[h],i,j)) || (in(A[h],i,j) && !in(B[h],i,j))) {
                vis[i][j] = 1;
                break;
            }
            }
        }
        }
        for(int d = 2 ; d <= 2 * N ; d += 2) {
        for(int i = 1 ; i <= 2 * N ; ++i) {
            int j = i + d - 1;
            if(j > 2 * N) break;
            if(vis[i][j]) continue;
            int x = j - i + 1 - 2 * cnt[i][j];
            dp[i][j] = g[x];
            for(int h = i + 1 ; h < j ; h += 2) {
            if(!dp[i][h]) continue;
            x = j - h - 2 * cnt[h + 1][j]; 
            dp[i][j] = inc(dp[i][j],MOD - mul(dp[i][h],g[x]));
            }
        }
        }
        int ans = 0;
        for(int i = 1 ; i <= 2 * N ; ++i) {
        for(int j = i + 1 ; j <= 2 * N ; j += 2) {
            int y = 2 * N - (j - i + 1 - 2 * cnt[i][j]) - 2 * K; 
            ans = inc(ans,mul(dp[i][j],g[y]));
        }
        }
        out(ans);enter;
    }
     
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
    }

E - High Elements

咱們須要已知部分\(X\)\(Y\)的狀況下,知道後面的數能不能使得最終狀況合法

咱們設\(X\)高元素的個數爲\(C_x\)\(Y\)高元素個數爲\(C_y\)

咱們還須要兩個高元素序列\(a,b\)知足\(C_x + |a| = C_y + |b|\)

咱們能夠保證\(a,b\)至少有一個,其中全部的高元素都是p原來的高元素,證實這個,咱們只要找到兩個合法的序列,而後每次減小兩個序列中高元素,直到不能減了

這樣的話咱們設\(a\)全是P原來的高元素組成的序列

而後咱們決定一下\(b\)\(b\)肯定了\(a\)就自動是未選的全部高元素了

\(b\)中的高元素有\(k\)個是P中的高元素,\(m\)是非高元素,剩下的序列中有Q個是高元素

那麼咱們知足
\(C_x + Q - k = C_y + |b|\)
\(C_x + Q - k = C_y + k + m\)
\(2k + m = C_x - C_y + Q\)

也就是咱們設全部高元素長度爲2,非高元素長度爲1,求一個上升子序列,看看長度是否正好爲一個常數

咱們只須要分奇偶性找一個最長的升子序列,和這個常數比較一下就行
須要用線段樹維護dp狀態

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define MAXN 200005
//#define ivorysi
#define space putchar(' ')
#define enter putchar('\n')
using namespace std;
typedef long long int64;
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 + c - '0';
    c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;}
    if(x >= 10) {
    out(x / 10);
    }
    putchar('0' + x % 10);
}
int N,P[MAXN],val[MAXN],ans[MAXN],curx,cury;
struct node {
    int maxv,L,R,lc,rc;
}tr[MAXN * 20];
int rt[2],Ncnt;
void build(int &u,int L,int R,int v) {
    u = ++Ncnt;
    tr[u].L = L;tr[u].R = R;
    tr[u].maxv = v;
    if(L == R) return;
    int mid = (L + R) >> 1;
    build(tr[u].lc,L,mid,v);
    build(tr[u].rc,mid + 1,R,v);
}
void Change(int u,int pos,int v) {
    if(tr[u].L == tr[u].R) {tr[u].maxv = v;return;}
    int mid = (tr[u].L + tr[u].R) >> 1;
    if(pos <= mid) Change(tr[u].lc,pos,v);
    else Change(tr[u].rc,pos,v);
    tr[u].maxv = max(tr[tr[u].lc].maxv,tr[tr[u].rc].maxv);
}
int Query(int u,int l,int r) {
    if(tr[u].L == l && tr[u].R == r) return tr[u].maxv;
    int mid = (tr[u].L + tr[u].R) >> 1;
    if(r <= mid) return Query(tr[u].lc,l,r);
    else if(l > mid) return Query(tr[u].rc,l,r);
    else return max(Query(tr[u].lc,l,mid),Query(tr[u].rc,mid + 1,r));
}
void Solve() {
    read(N);
    for(int i = 1 ; i <= N ; ++i) read(P[i]);
    int cur = 0,Q = 0;
    for(int i = 1 ; i <= N ; ++i) {
    cur = max(cur,P[i]);
    if(cur == P[i]) {val[i] = 2;++Q;}
    else val[i] = 1;
    }
    build(rt[0],1,N + 1,0);build(rt[1],1,N + 1,-2 * N);
    for(int i = N ; i >= 1 ; --i) {
    int tmp[2];
    for(int j = 0 ; j < 2 ; ++j) tmp[j] = Query(rt[j],P[i] + 1,N + 1);
    for(int j = 0 ; j < 2 ; ++j) {
        if(tmp[j] + val[i] > 0) {
        int t = (tmp[j] + val[i]) & 1;
        Change(rt[t],P[i],tmp[j] + val[i]);
        }
    }
    }
    int len[2] = {0,0},mx_num[2] = {0,0};
    for(int i = 1 ; i <= N ; ++i) {
    ans[i] = -1;
    Change(rt[0],P[i],0);Change(rt[1],P[i],-2 * N);
    if(val[i] == 2) --Q;
    for(int k = 0 ; k < 2 ; ++k) {
        int nxt_len[2],nxt_mx_num[2];
        memcpy(nxt_len,len,sizeof(len));
        memcpy(nxt_mx_num,mx_num,sizeof(mx_num));
        nxt_mx_num[k] = max(nxt_mx_num[k],P[i]);
        if(nxt_mx_num[k] == P[i]) ++nxt_len[k];
        if(i == N) {
        if(nxt_len[0] == nxt_len[1]) {ans[i] = k;break;}
        continue;
        }
        bool flag = 0;
        
        for(int j = 0 ; j < 2 ; ++j) {
        int t = nxt_len[j] - nxt_len[j ^ 1] + Q;
        if(t >= 0 && Query(rt[t & 1],nxt_mx_num[j ^ 1] + 1,N + 1) >= t) {flag = 1;break;}
        }
        if(flag) {
        ans[i] = k;
        memcpy(len,nxt_len,sizeof(len));
        memcpy(mx_num,nxt_mx_num,sizeof(mx_num));
        break;
        }
    }
    if(ans[i] < 0) {
        puts("-1");return;
    }
    }
    for(int i = 1 ; i <= N ; ++i) putchar('0' + ans[i]);
    enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}
相關文章
相關標籤/搜索