1. 程式人生 > >【AtCoder】Mujin Programming Challenge 2017

【AtCoder】Mujin Programming Challenge 2017

res template 階乘 set utc can 處理 兩個 oid

Mujin Programming Challenge 2017

A - Robot Racing

如果每個數都是一個一個間隔開的,那麽答案是\(n!\)

考慮把一個數挪到1,第二個數挪到3,以此類推,如果不行,證明前面中有個數肯定會被選擇,所以任意選一個數到終點,繼續這樣的操作

最後剩下的乘一個階乘即可

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define eps 1e-10
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef unsigned int u32;
typedef double db;
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);
}
const int MOD = 1000000007;
int N,ans;
int x[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);
}
void Solve() {
    read(N);
    for(int i = 1 ; i <= N ; ++i) read(x[i]);
    int pre = 0;
    int cnt = 0,ans = 1;
    for(int i = 1 ; i <= N ; ++i) {
        if(x[i] > pre) {++cnt;pre += 2;}
        else ans = mul(ans,cnt + 1);
    }
    for(int i = 1 ; i <= cnt ; ++i) ans = mul(ans,i);
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

B - Row to Column

顯然我們必須先恢復出一行來,然後去更新一開始沒有全滿的列

要麽是第j列有黑格子,我們用它去恢復出第j行,要麽給第j列創造一個黑格子,恢復出第j行

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define eps 1e-10
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef unsigned int u32;
typedef double db;
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;
char s[505][505];
int sumr[505],sumc[505];
bool vis[505];
void Solve() {
    read(N);
    bool flag = 0;
    for(int i = 1 ; i <= N ; ++i) {
        scanf("%s",s[i] + 1);
        for(int j = 1 ; j <= N ; ++j) {
            if(s[i][j] == '#') flag = 1;
        }
    }
    if(!flag) {
        puts("-1");return;
    }
    for(int i = 1 ; i <= N ; ++i) {
        for(int j = 1 ; j <= N ; ++j) {
            if(s[i][j] == '#') vis[j] = 1;
        }
    }
    int cnt = 0;
    for(int j = 1 ; j <= N ; ++j) {
        int c = 0;
        for(int i = 1 ; i <= N ; ++i) {
            c += (s[i][j] == '#');
        }
        if(c == N) ++cnt;
    }
    int ans = 2 * N;
    for(int i = 1 ; i <= N ; ++i) {
        int c = 0;
        for(int j = 1 ; j <= N ; ++j) {
            c += (s[i][j] == '.');
        }
        ans = min(ans,c + N - cnt + (vis[i] ^ 1));
    }
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

C - Robot and String

用處理出\(nxt(l)\)表示l之後到第幾個位置能變成空

同時記錄\(nxt_{a}(l),nxt_{b}(l)\)一直到z,初始時候先把s[l + 1]的數設成l + 1,然後從這個位置開始循環更新

然後我們一次詢問就是不斷的\(nxt(l - 1)\)嵌套,我們處理出2的次冪次操作即可

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define eps 1e-10
#define MAXN 500005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef unsigned int u32;
typedef double db;
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;
char s[MAXN];
int nxt[MAXN][27],ri[MAXN][27];
void Solve() {
    scanf("%s",s + 1);
    N = strlen(s + 1);
    for(int i = 0 ; i <= N + 1; ++i) {
        for(int j = 0 ; j <= 26 ; ++j) {
            nxt[i][j] = N + 1;
        }
    }
    for(int i = 0 ; i <= N + 1 ; ++i) {
        for(int j = 0 ; j <= 19 ; ++j) ri[i][j] = N + 1;
    }
    for(int i = N - 1 ; i >= 0 ; --i) {
        int x = s[i + 1] - 'a';
        nxt[i][x] = i + 1;
        for(int j = x + 1 ; j <= 26 ; ++j) {
            nxt[i][j] = nxt[nxt[i][j - 1]][j - 1];
        }
        for(int j = 0 ; j < x ; ++j) {
            nxt[i][j] = nxt[nxt[i][26]][j];
        }
    }
    for(int j = 0 ; j <= 19 ; ++j) {
        for(int i = N - 1 ; i >= 0 ; --i) {
            if(j == 0) ri[i][j] = nxt[i][26];
            else ri[i][j] = ri[ri[i][j - 1]][j - 1];
        }
    }
    int Q;
    read(Q);
    int l,r;
    for(int i = 1 ; i <= Q ; ++i) {
        read(l);read(r);
        --l;
        for(int j = 19 ; j >= 0 ; --j) {
            if(ri[l][j] <= r) l = ri[l][j];
        }
        if(l == r) puts("Yes");
        else puts("No");
    }
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

D - Oriented Tree

顯然D是直徑上取整

然後我們給每個點做一個標號,任取一個點\(h(v) = 0\)

如果\(u\rightarrow v\)有一條邊那麽\(h(v) - h(u) = 1\)

最後可以定義\(d(s,t) = (dist(s,t) + h(s) - h(t))/ 2\)

如果直徑是偶數,那麽可以發現

\(|h(s) - h(t)| \leq 2D - dist(s,t)\)

找到直徑的中心\(r\),距離中心距離為\(D\)的點,顯然標號應該一樣,假設標號都是0,我們可以得到任意一點u都有\(|h(u)| \leq D - dist(r,u)\)

這個是必要的,也是充分的,對於任意兩點\(u,v\)

\(|h(u) - h(v)| \leq |h(u)| + |h(v)| \leq 2D - dist(r,u) - dist(r,v) \leq 2D - dist(u,v)\)

所以我們認為\(|h(u)| \leq D - dist(r,u)\),做一個dp,可以得到所有解

如果直徑是奇數,就有了兩個中心,一個是s,一個是t

我們認為\(dist(u,s) < dist(t,u)\)的是白點,否則是黑點,那麽有兩種情況

如果u是白點,\(|h(u)| \leq D - 1 - dist(u,s)\)

如果u是黑點,\(|h(u)| \leq D - dist(u,t)\)

或者

u是白點,\(|h(u)| \leq D - dist(u,s)\)

u是黑點,\(|h(u)| \leq D - 1 - dist(u,t)\)

但是這兩種情況有交集

就是白點的距離s最遠的點全是0,另一邊距離最遠的全是-1,或者全是+1,這個時候我們如果所有點同時-1或者同時+1,會發現這兩種情況等價但是我們重復統計了

這個時候條件是

u是白點,\(|h(u)| \leq D - dist(u,s)\)

u是黑點,\(|h(u) + 1| \leq D - dist(u,t)\)

或者是

u是白點,\(|h(u)| \leq D - dist(u,s)\)

u是黑點,\(|h(u) - 1| \leq D - dist(u,t)\)

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define eps 1e-10
#define MAXN 1005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef unsigned int u32;
typedef double db;
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);
}
const int MOD = 1000000007,V = 505;
struct node {
    int to,next;
}E[MAXN * 2];
int sumE,head[MAXN];
int N;
int dis[MAXN],fa[MAXN],D;
int dp[MAXN][MAXN * 2];
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);
}
void add(int u,int v) {
    E[++sumE].to = v;
    E[sumE].next = head[u];
    head[u] = sumE;
}
void dfs(int u) {
    for(int i = head[u] ; i ; i = E[i].next) {
        int v = E[i].to;
        if(v != fa[u]) {
            fa[v] = u;
            dis[v] = dis[u] + 1;
            dfs(v);
        }
    }
}
void dfs1(int u,int lim,int on) {
    for(int i = head[u] ; i ; i = E[i].next) {
        int v = E[i].to;
        if(v != fa[u]) {
            dfs1(v,lim,on);
        }
    }
    int l = dis[u] - lim - on,r = lim - dis[u] - on;
    for(int i = l + V ; i <= r + V; ++i) {
        dp[u][i] = 1;
        for(int j = head[u] ; j ; j = E[j].next) {
            int v = E[j].to;
            if(v != fa[u]) {
                int t = inc(dp[v][i - 1],dp[v][i + 1]);
                dp[u][i] = mul(dp[u][i],t);
            }
        }
    }
}
int Process_even(int rt) {
    fa[rt] = 0;dis[rt] = 0;
    dfs(rt);
    memset(dp,0,sizeof(dp));
    dfs1(rt,D,0);
    int ans = 0;
    for(int i = 0 ; i <= V * 2 ; ++i) {
        update(ans,dp[rt][i]);
    }
    return ans;
}
int Process_odd(int s,int t,int on) {
    fa[s] = t;fa[t] = s;dis[s] = 0;dis[t] = 0;
    dfs(s);dfs(t);
    memset(dp,0,sizeof(dp));
    dfs1(s,D - 1,0);
    dfs1(t,D,on);
    int ans = 0;
    for(int i = 1 ; i <= V * 2 ; ++i) {
        update(ans,mul(dp[s][i],inc(dp[t][i - 1],dp[t][i + 1])));
    }
    return ans;
}
void Solve() {
    read(N);
    int a,b;
    for(int i = 1 ; i < N ; ++i) {read(a);read(b);add(a,b);add(b,a);}
    dis[1] = 0;fa[1] = 0;dfs(1);
    int u = 1;
    for(int i = 2 ; i <= N ; ++i) {
        if(dis[i] > dis[u]) u = i;
    }
    dis[u] = 0;fa[u] = 0;
    dfs(u);
    u = 1;
    for(int i = 2 ; i <= N ; ++i) {
        if(dis[i] > dis[u]) u = i;
    }
    if(dis[u] % 2 == 0) {
        int r = u;
        for(int i = 1 ; i <= dis[u] / 2 ; ++i) r = fa[r];
        D = dis[u] / 2;
        int ans = Process_even(r);
        out(ans);enter;
    }
    else {
        int s = u;
        for(int i = 1 ; i <= dis[u] / 2 ; ++i) s = fa[s];
        int t = fa[s];
        D = dis[u] / 2 + 1;
        int ans = inc(Process_odd(s,t,0),Process_odd(t,s,0));
        update(ans,MOD - Process_odd(s,t,-1));
        update(ans,MOD - Process_odd(s,t,1));
        out(ans);enter;
    }
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

【AtCoder】Mujin Programming Challenge 2017