1. 程式人生 > >【AtCoder】ARC099題解

【AtCoder】ARC099題解

C - Minimization

每次操作必然包含一個1
列舉第一次操作的位置計算兩邊即可

程式碼

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define space putchar(' ')
#define enter putchar('\n')
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
template<class T>
void read(T &res) {
    res = 0;T f = 1;char c = getchar();
    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,K;
int a[MAXN],pos[MAXN];
int C(int x) {
    return x % (K - 1) == 0 ? x / (K - 1) : x / (K - 1) + 1;
}
void Solve() {
    read(N);read(K);
    for(int i = 1 ; i <= N ; ++i) {read(a[i]);pos[a[i]] = i;}
    int ans = N;
    for(int i = 1 ; i <= N ; ++i) {
    if(i + K - 1 >= pos[1]) {
        ans = min(ans,C(i - 1) + C(N - min((i + K - 1),N)) + 1);
    }
    }
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

D - Snuke Numbers

我們對於N 只要能求出\(f(N + 1)\)(\(f(x)\)表示大於等於\(x\)的數中\(\frac{x}{S(x)}\)最小的那個)
那麼就能不斷找到下一個數了

怎麼求呢,我們可以認為一個可以被取到的數一定是x的一段字首,加上中間某個數修改,後面的所有數都改成9

因為999999...9999是一個合法的數,那麼可以認為\(f(x)\)的位數和\(x\)一定相同

如果我們找到一個數\(a\),它的第d位與x不同,且它後面不都是9,那麼我們可以把第d位-1,後面全部修改成9

所以我們找的數的數目有限,都找出來找最小的\(\frac{x}{S(x)}\)

即可

程式碼

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define space putchar(' ')
#define enter putchar('\n')
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
template<class T>
void read(T &res) {
    res = 0;T f = 1;char c = getchar();
    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 K,t[25],tot,cnt,s[10005];
int64 L[10005],p[25],b[25];
int S(int64 x) {
    int res = 0;
    while(x) {res += x % 10;x /= 10;}
    return res;
}

int64 f(int64 x) {
    tot = 0;cnt = 0;int64 h = x;
    while(h) {t[++tot] = h % 10;h /= 10;}
    int64 num = 0;
    for(int i = tot ; i >= 1 ; --i) {
    for(int j = t[i] ; j <= 9 ; ++j) {
        int64 tmp = num + j * b[i - 1] + p[i - 1];
        if(tmp >= x) L[++cnt] = tmp;
    }
    num = num + t[i] * b[i - 1];
    }
    
    for(int i = 1 ; i <= cnt ; ++i) s[i] = S(L[i]);
    int r = 1;
    for(int i = 2 ; i <= cnt ; ++i) {
    int64 h = L[i] * s[r] - L[r] * s[i];
    if(h < 0) r = i;
    else if(h == 0 && L[i] < L[r]) r = i; 
    }
    return L[r];
}
void Solve() {
    read(K);
    int64 N = 1;
    p[1] = 9;
    for(int i = 2 ; i <= 16 ; ++i) p[i] = p[i - 1] * 10 + 9;
    b[0] = 1;
    for(int i = 1 ; i <= 16 ; ++i) b[i] = b[i - 1] * 10;
    while(K--) {
    out(N);enter;
    N = f(N + 1);
    }
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

E - Independence

反圖必然是個二分圖,不然則無解

我們希望知道哪些分的情況可以達到,就直接把一個二分圖的聯通塊拿出來,做分組揹包即可

程式碼

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define space putchar(' ')
#define enter putchar('\n')
#define MAXN 100005
#define mp make_pair
//#define ivorysi
using namespace std;
typedef long long int64;
template<class T>
void read(T &res) {
    res = 0;T f = 1;char c = getchar();
    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,M;
int g[705][705];
struct node {
    int to,next;
}E[1000005];
int sumE,head[705],tot,col[705],que[705],qr;
pii conn[705];
bool f[2][705];
void add(int u,int v) {
    E[++sumE].next = head[u];
    E[sumE].to = v;
    head[u] = sumE;
}
bool dfs(int u) {
    if(col[u] == -1) col[u] = 0;
    que[++qr] = u;
    for(int i = head[u] ; i ; i = E[i].next) {
    int v = E[i].to;
    if(col[v] == col[u]) return false;
    else if(col[v] == -1) {
        col[v] = col[u] ^ 1;
        if(!dfs(v)) return false;
    }
    }
    return true;
}
void Solve() {
    read(N);read(M);
    int u,v;
    for(int i = 1 ; i <= M ; ++i) {
    read(u);read(v);
    g[u][v] = g[v][u] = 1;
    }
    for(int i = 1 ; i <= N ; ++i) {
    for(int j = i + 1 ; j <= N ; ++j) {
        if(!g[i][j]) {add(i,j);add(j,i);}
    }
    }
    memset(col,-1,sizeof(col));
    for(int i = 1 ; i <= N ; ++i) {
    if(col[i] == -1) {
        qr = 0;
        if(!dfs(i)) {puts("-1");return;}
        int cnt[2] = {0,0};
        for(int j = 1 ; j <= qr ; ++j) cnt[col[que[j]]]++;
        conn[++tot] = mp(cnt[0],cnt[1]);
    }
    }
    int cur = 0;
    f[0][0] = 1;
    for(int i = 1 ; i <= tot ; ++i) {
    memset(f[cur ^ 1],0,sizeof(f[cur ^ 1]));
    for(int j = N ; j >= 0 ; --j) {
        if(j >= conn[i].fi) f[cur ^ 1][j] |= f[cur][j - conn[i].fi];
        if(j >= conn[i].se) f[cur ^ 1][j] |= f[cur][j - conn[i].se];
    }
    cur ^= 1;
    }
    int ans = N * N;
    for(int i = 0 ; i <= N ; ++i) {
    if(f[cur][i]) {
        ans = min(i * (i - 1) / 2 + (N - i) * (N - i - 1) / 2,ans);
    }
    }
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

F - Eating Symbols Hard

一道神奇的題

我們把操作S構成的A陣列用一個多項式表示出來
\(t(S) = \sum_{i = -10^9}^{10^9} A_{i}X^{i}\)
如果往S前面新增一個字元的話
\(t<(S) = t(S)X^{-1}\)
\(t>(S) = t(S)X\)
\(t+(S) = t(S) + 1\)
\(t-(S) = t(S) - 1\)
那麼我們對於最終的序列求一個雜湊值c,如果一段區間操作後的結果和c一樣的話就有
\(t_{S_i}t_{S_{i + 1}}...t_{S_j}(0) = c\)
由於這些操作可逆,可以一層一層拆開
可以得到
\(t_{S_N}^{-1}...t_{S_i}^{-1}t_{S_i}t_{S_{i + 1}}...t_{S_j}(0) = t_{S_N}^{-1}...t_{S_i}^{-1}(c)\)
那麼我們可以得到
\(t_{S_N}^{-1}...t_{S_{j + 1}}^{-1} (0) = t_{S_N}^{-1}...t_{S_{i}}^{-1}(c)\)
這個字尾積可以線性處理出來,維護未知數前的係數即可

然後就是愉快的用map查詢了

那麼,衝突怎麼考慮?題解說是衝突的概率在2N/模數大小,讓用6個,然而我寫的不優美,T掉了,改成5個卡著時限A了,感覺用不上太多也是對的啊

程式碼

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <map>
#define enter putchar('\n')
#define space putchar(' ')
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define pii pair<int,int>
#define eps 1e-7
#define MAXN 250005
#define MOD 999999137
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
typedef vector<int> poly;
 
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);
}
int B[] = {0,823,727,401,271,571};
int InvB[10];
int f[8][MAXN],g[8][MAXN],N,h[8][MAXN];
char s[MAXN];
map<int,int> MK[8];
 
 
int mul(int a,int b) {
    return 1LL * a * b % MOD;
}
int inc(int a,int b) {
    return a + b >= MOD ? a + b - MOD : a + b;
}
void update(int &x,char c,int id) {
    if(c == '<') x = mul(x,InvB[id]);
    else if(c == '>') x = mul(x,B[id]);
    else if(c == '+') x = inc(x,1);
    else x = inc(x,MOD - 1);
}
int fpow(int x,int c) {
    int res = 1,t = x;
    while(c) {
        if(c & 1) res = mul(res,t);
        t = mul(t,t);
        c >>= 1;
    }
    return res;
}
void Solve() {
    for(int i = 1 ; i <= 5 ; ++i) InvB[i] = fpow(B[i],MOD - 2);
    read(N);
    scanf("%s",s + 1);
    int c[10] = {0};
    for(int k = 1 ; k <= 5 ; ++k) {
        for(int i = N ; i >= 1 ; --i) {
            update(c[k],s[i],k);
        }
    }
    for(int k = 1 ; k <= 5 ; ++k) h[k][N + 1] = 1,g[k][N + 1] = c[k],MK[k][0] += 1;
    int64 ans = 0;
    for(int i = N ; i >= 1 ; --i) {
        int add = N - i + 1;
        for(int k = 1 ; k <= 5 ; ++k) {
            if(s[i] == '<') {
                g[k][i] = inc(g[k][i + 1],MOD - mul(h[k][i + 1],c[k]));
                h[k][i] = mul(h[k][i + 1],B[k]);
                g[k][i] = inc(g[k][i],mul(h[k][i],c[k]));
                f[k][i] = f[k][i + 1];      
            }
            else if(s[i] == '>') {
                g[k][i] = inc(g[k][i + 1],MOD - mul(h[k][i + 1],c[k]));
                h[k][i] = mul(h[k][i + 1],InvB[k]);
                g[k][i] = inc(g[k][i],mul(h[k][i],c[k]));
                f[k][i] = f[k][i + 1];
            }
            else if(s[i] == '+') {
                h[k][i] = h[k][i + 1];
                g[k][i] = inc(g[k][i + 1],MOD - h[k][i]);
                f[k][i] = inc(f[k][i + 1],MOD - h[k][i]);
            }
            else {
                h[k][i] = h[k][i + 1];
                g[k][i] = inc(g[k][i + 1],h[k][i]);
                f[k][i] = inc(f[k][i + 1],h[k][i]);
            }
            add = min(add,MK[k][g[k][i]]);
            MK[k][f[k][i]] += 1;
        }
        ans += add;
    }
    out(ans);enter; 
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
    return 0;
}