【AtCoder】AtCoder Petrozavodsk Contest 001

A - Two Integers

若是\(X\)\(Y\)的倍數的話不存在
能夠輸出\(X \cdot (\frac{Y}{gcd(X,Y)} - 1)\)node

代碼

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 100005
#define eps 1e-8
//#define ivorysi
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 + 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 X,Y;
int64 gcd(int64 a,int64 b) {
    return b == 0 ? a : gcd(b,a % b);
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    read(X);read(Y);
    if(X % Y == 0) {puts("-1");return 0;}
    int64 t = Y / gcd(X,Y);
    out(X * (t - 1));enter;
}

B - Two Arrays

a<b的話,這個位置必定會合法,若是a > b的話不可能再小於b了,因此咱們看看在用全部位置的a增長不超過b的位置的狀況下,能一共給b增長多少,若是這個增長數大於全部a > b的a和b差值的和就合法c++

代碼

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 100005
#define eps 1e-8
//#define ivorysi
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 + 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 a[MAXN],b[MAXN],N;
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    read(N);
    for(int i = 1 ; i <= N ; ++i) read(a[i]);
    for(int i = 1 ; i <= N ; ++i) read(b[i]);
    int64 all = 0;
    for(int i = 1 ; i <= N ; ++i) {
        if(a[i] > b[i]) all += a[i] - b[i];
        else all -= (b[i] - a[i]) / 2;
    }
    if(all > 0) puts("No");
    else puts("Yes");
}

C - Vacant Seat

二分
我知道了最左和最右兩邊的後,若是這個位置和兩邊都是奇數區間的話
例如
1 *** 0 *** 0
那麼空位在左邊
若是兩邊都是偶數長的話
例如
1 **** 0 **** 0
那麼空位在右邊數組

代碼

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 100005
#define eps 1e-8
//#define ivorysi
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 + 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;
int num[2];
char s[15];
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    read(N);
    out(0);enter;fflush(stdout);
    scanf("%s",s + 1);

    if(s[1] == 'F') num[0] = 1;
    else if(s[1] == 'M') num[0] = 0;
    else return 0;
    out(N - 1);enter;fflush(stdout);
    scanf("%s",s + 1);

    if(s[1] == 'F') num[1] = 1;
    else if(s[1] == 'M') num[1] = 0;
    else return 0;
    int L = 1,R = N - 2;
    while(L < R) {
        int mid = (L + R) >> 1;
        out(mid);enter;fflush(stdout);
        scanf("%s",s + 1);

        if(s[1] == 'V') return 0;
        int a;
        if(s[1] == 'M') a = 0;
        else a = 1;
        int t = a ^ ((mid - L) & 1);
        if(t == num[0]) {R = mid - 1;num[1] = a;}
        else {L = mid + 1;num[0] = a;}
    }
    out(L);enter;fflush(stdout);scanf("%s",s + 1);
    return 0;
}

D - Forest

把每一個點排序,若是加進來的點所在的聯通塊沒有點,那麼把這個點放進隊列裏,若是還有別的聯通塊裏的點,就把這個點和別的聯通塊連一條邊,而後刪掉這個點,把這兩個聯通塊用並查集連在一塊兒spa

若是沒有別的聯通塊裏的點,那麼就把這個點扔進隊列,把隊列打上標記,若是以後還有別的聯通塊的點來,而後取出隊列裏這個聯通塊中的點和新加的點連一條邊
直到隊列裏只有一個點就把標記刪除rest

若是隻有兩個聯通塊,隊列沒有標記,且有多於兩個點,這兩個點之間連一條邊退出就行了code

保證每次都是取了最小的兩個點連邊(第一種操做也是保證取了最小的由於我保證了在隊列裏同聯通塊的點必定會被用,因此這個點也可用)排序

代碼

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 100005
#define eps 1e-8
//#define ivorysi
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 + 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,id[MAXN],conn;
int64 a[MAXN];
int fa[MAXN];
bool vis[MAXN];
int que[MAXN],ql,qr;
bool flag = 0;
bool cmp(int s,int t) {
    return a[s] < a[t];
}
int getfa(int x) {
    return fa[x] == x ? x : fa[x] = getfa(fa[x]);
}
void Solve() {
    read(N);read(M);
    for(int i = 1 ; i <= N ; ++i) {read(a[i]);id[i] = i;}
    sort(id + 1,id + N + 1,cmp);
    for(int i = 1 ; i <= N ; ++i) fa[i] = i;
    int x,y;
    conn = N;
    for(int i = 1 ; i <= M ; ++i) {
        read(x);read(y);
        ++x;++y;
        conn--;
        fa[getfa(x)] = getfa(y);
    }
    if(conn == 1) {puts("0");return;}
    ql = 1,qr = 0;
    int64 ans = 0;
    for(int i = 1 ; i <= N ; ++i) {
        int u = id[i];
        if(flag) {
            if(getfa(u) == getfa(que[ql])) que[++qr] = u;
            else {
                ans += a[que[ql]] + a[u];
                --conn;
                fa[getfa(u)] = getfa(que[ql]);
                ql++;
                if(qr == ql) flag = 0;
            }
        }
        else {
            if(vis[getfa(u)]) {
                if(ql == qr) {flag = 1;que[++qr] = u;}
                else if(getfa(que[ql]) == getfa(u)) {
                    ans += a[que[ql]] + a[que[ql + 1]];
                    --conn;
                    fa[getfa(que[ql + 1])] = getfa(que[ql]);
                    ql += 2;
                    que[++qr] = u;
                }
                else {
                    ans += a[u] + a[que[ql]];
                    --conn;
                    fa[getfa(que[ql])] = getfa(u);
                    ql++;
                }

            }
            else {
                que[++qr] = u;vis[getfa(u)] = 1;
            }
        }
        if(conn == 1) break;
        if(conn == 2 && qr - ql + 1 >= 2 && !flag) {
            ans += a[que[ql]] + a[que[ql + 1]];
            --conn;
            break;
        }
    }
    if(conn != 1) {puts("Impossible");}
    else {out(ans);enter;}
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
    return 0;
}

E - Antennas on Tree

簡單的樹dp隊列

\(dp[v]\)爲以0爲根時\(v\)點子樹裏最少須要選擇的點get

\(dp[u] = \sum_{v\in son(u)} dp[v]\)
計算一個\(cnt\)\(v\)\(dp[v]\)不爲0的個數
$dp[u] += max(0,son - 1 - cnt) $it

而後就是換根了,不難換具體看代碼吧

題解

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define MAXN 100005
#define mo 974711
//#define ivorysi
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 + 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);
}

struct node {
    int to,next;
}E[MAXN * 2];
int head[MAXN],sumE,N,ans;
int dp[MAXN],fr[MAXN];
void add(int u,int v) {
    E[++sumE].to = v;
    E[sumE].next = head[u];
    head[u] = sumE;
}
void dfs1(int u,int fa) {
    int son = 0,cnt = 0;
    for(int i = head[u] ; i ; i = E[i].next) {
    int v = E[i].to;
    if(v != fa) {
        ++son;
        dfs1(v,u);
        if(dp[v]) ++cnt;
        dp[u] += dp[v];
    }
    }
    if(cnt < son - 1) dp[u] += son - 1 - cnt;
}
void dfs2(int u,int fa) {
    int sum = 0,son = 0,cnt = 0;
    if(fa != -1) {
    sum = 0,son = 0,cnt = 0;
    for(int i = head[u] ; i ; i = E[i].next) {
        int v = E[i].to;
        if(v != fa) {
        ++son;
        sum += dp[v];
        if(dp[v]) ++cnt;
        }
    }
    ++son;sum += fr[u];if(fr[u]) ++cnt;
    if(cnt < son - 1) sum += son - 1 - cnt;
    ans = min(ans,sum + 1);
    }
    sum = 0,son = 0,cnt = 0;
    if(fa != -1) {sum += fr[u];++son;if(fr[u]) ++cnt;}
    for(int i = head[u] ; i ; i = E[i].next) {
    int v = E[i].to;
    if(v != fa) {
        ++son;
        sum += dp[v];
        if(dp[v]) ++cnt;
    }
    }
    for(int i = head[u] ; i ; i = E[i].next) {
    int v = E[i].to;
    if(v != fa) {
        int t = dp[v] > 0;
        fr[v] = sum - dp[v];
        if(son - 2 > cnt - t) fr[v] += son - 2 - cnt + t;
        dfs2(v,u);
    }
    }
}
void Solve() {
    int x,y;
    read(N);
    for(int i = 1 ; i < N ; ++i) {
    read(x);read(y);
    add(x,y);add(y,x);
    }
    dfs1(0,-1);
    ans = dp[0] + 1;
    dfs2(0,-1);
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

F - XOR Tree

若是你很熟練,你能夠想到給一條路徑加異或就至關於給兩個端點到根加異或

咱們從底到根算出每一個點都須要加多少異或,而後給相同的異或值兩兩配對,這個時候會有單出來的

例如
1 2 3
咱們能夠2次解決而不是3次

咱們設\(f[S]\)\(S\)集合中的點所須要最少的操做次數,\(S\)裏的異或值爲0時,初始值是\(S\)中1的個數-1,不然爲\(S\)中1的個數

而後用子集枚舉計算,複雜度是\(3^15\)

代碼

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 100005
#define eps 1e-8
//#define ivorysi
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 + 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;
struct node {
    int to,next,val;
}E[MAXN * 2];
int head[MAXN],sumE;
int C[MAXN],cnt[25],f[(1 << 15) + 5],siz[MAXN];
void add(int u,int v,int c) {
    E[++sumE].to = v;
    E[sumE].next = head[u];
    E[sumE].val = c;
    head[u] = sumE;
}
void dfs(int u,int fa) {
    for(int i = head[u] ; i ; i = E[i].next) {
        int v = E[i].to;
        if(v != fa) {
            C[v] ^= E[i].val;
            dfs(v,u);
            siz[u] ^= siz[v];
        }
    }
    C[u] ^= siz[u];
    siz[u] ^= C[u];
}
void Solve() {
    read(N);
    int x,y,a;
    for(int i = 1 ; i < N ; ++i) {
        read(x);read(y);read(a);
        add(x,y,a);add(y,x,a);
    }
    dfs(0,-1);
    for(int i = 1 ; i < N ; ++i) {
        cnt[C[i]]++;
    }
    int ans = 0,q = 0;
    for(int i = 1 ; i <= 15 ; ++i) {
        ans += cnt[i] / 2;
        cnt[i] %= 2;
        if(cnt[i]) q |= 1 << (i - 1);
    }
    for(int i = 1 ; i < (1 << 15) ; ++i) {
        int a = 0,c = 0;
        for(int j = 1 ; j <= 15 ; ++j) {
            if(i >> (j - 1) & 1) {
                a ^= j;
                ++c;
            }
        }
        if(!a) f[i] = c - 1;
        else f[i] = c;
    }
    for(int S = 1 ; S < (1 << 15) ; ++S) {
        for(int T = (S - 1) & S ; T ; T = (T - 1) & S) {
            f[S] = min(f[S],f[T] + f[S ^ T]);
        }
    }
    ans += f[q];
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
    return 0;
}

G - Colorful Doors

在好久之前的NOI集訓……我曾經見過這題……而後成功爆0

如今我仍是看不懂orz

分類討論大題真是

咱們把首尾的兩個門連起來,至關於一個環

考慮全覆蓋的狀況,若是N是偶數
咱們能夠
1 2 1 2 3 4 3 4這麼覆蓋
若是N是奇數,因爲1的時候有兩個環以後N每+1環個數的奇偶性改變,咱們總到不了一個環的時候,因此無解

而後咱們若是有一個串010110111
咱們在前面加上一個1

變成1010110111

咱們統計一下兩邊都是1的門的個數,記爲sum

若是sum 是奇數,顯然不存在,由於兩邊都是1的門要兩兩配對

若是sum是4的倍數,咱們把兩端連續的1最後一個和第一個寫成一樣字母,能夠變成所有覆蓋且N爲偶數的狀況

若是sum是偶數
那麼若是這些兩邊都是1的門是連到一塊兒的,就至關於N是奇數的狀況

若是兩邊都是1的門至少有兩段分開的,咱們就能夠
1->2->3 4->5->6把2和5變成一種顏色,而後就變成了1->25->6->4->52->3這樣的鏈

代碼

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define MAXN 200005
#define mo 974711
//#define ivorysi
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 + 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,ans[MAXN],tot,t[MAXN],to[MAXN];
char s[MAXN];
vector<int> f;
bool vis[MAXN];
void Solve() {
    read(N);
    scanf("%s",s + 2);
    s[1] = '1';
    int cnt = 0;
    for(int i = 1 ; i < 2 * N ; ++i) {
        if(s[i] == '1' && s[i + 1] == '1') {++cnt;t[i] = 1;}
    }
    if(s[2 * N] == '1') {++cnt;t[2 * N] = 1;}
    if(cnt & 1) {puts("No");return;}
    bool flag = 0;
    if(cnt % 4 != 0) {
    int a = 1,b = 2 * N;
    int c = 0;
    while(t[a] == 1 && a <= 2 * N) ++a;
    --a;

    while(t[b] == 1 && b >= 1) --b;
        ++b;
        if(a > b) {puts("No");return;}
        if(a >= 1 || b <= 2 * N) ++c;
        for(int i = a + 1 ; i <= b - 1 ; ++i) {
            if(t[i] == 1 && t[i - 1] != 1) ++c;
        }
        if(c < 2) {puts("No");return;}
        if(c == 2 && a < 1 && b <= 2 * N) flag = 1;
    }
    puts("Yes");
    if(flag) {
        f.clear();
        int ano;
        for(int i = 1 ; i <= 2 * N ; ++i) {
            if(t[i] == 1) {
                ans[i] = ++tot;ans[2 * N] = tot;
                ano = i;
                break;
            }
        }
        int p = 2 * N;
        while(t[p] == 1) --p;
        ans[p] = ++tot;ans[1] = tot;
        for(int i = p + 1 ; i < 2 * N ; ++i) f.pb(i);
        p = ano;
        while(t[p] == 1) ++p;
        for(int i = ano + 1 ; i < p ; ++i) f.pb(i);
        while(1) {
            int h = p;
            while(s[h + 1] == '0') ++h;
            if(ans[h]) break;
            ans[h] = ++tot;ans[p] = tot;
            p = h + 1;
        }
        ans[p] = ++tot;ans[ano - 1] = tot;
        int siz = f.size();
        for(int i = 0 ; i < siz ; i += 4) {
            ans[f[i]] = ++tot;ans[f[i + 2]] = tot;
            ans[f[i + 1]] = ++tot;ans[f[i + 3]] = tot;
        }
        f.clear();
        for(int i = 1 ; i <= 2 * N ; ++i) if(!ans[i]) f.pb(i);
        siz = f.size();
        for(int i = 0 ; i < siz ; i += 2) {
            ans[f[i]] = ++tot;ans[f[i + 1]] = tot;
        }
        for(int i = 1 ; i <= 2 * N ; ++i) {out(ans[i]);space;}
        enter;
        return ;
    }
    if(cnt % 4 == 2) {

        for(int i = 1 ; i <= 2 * N ; ++i) {
            if(t[i] == 1 && t[i - 1] == 0) f.pb(i);
        }
        ans[f[0]] = ++tot;ans[f[1]] = tot;
        to[f[0]] = f[1] + 1;to[f[1]] = f[0] + 1;
        int k = f[1];
        while(t[k] == 1) ++k;
        ans[k] = ++tot;ans[f[1] - 1] = tot;
        to[k] = f[1] - 1;to[f[1] - 1] = k;
    }

    int p = 1;
    f.clear();
    while(p <= 2 * N) {
        vis[p] = 1;
        if(t[p] && !ans[p]) f.pb(p);
        if(p >= 2 * N) break;
        if(to[p] && !vis[to[p]]) p = to[p];
        else if(s[p + 1] == '1' && !vis[p + 1]) ++p;
        else {
            int k = p;
            while(k < 2 * N && (s[k + 1] == '0' || vis[k])) ++k;
            ans[p] = ++tot;ans[k] = tot;
            p = k + 1;
            while(p <= 2 * N && vis[p]) ++p;
        }

    }
    int siz = f.size();
    for(int i = 0 ; i < siz ; i += 4) {
        ans[f[i]] = ++tot;ans[f[i + 2]] = tot;
        ans[f[i + 1]] = ++tot;ans[f[i + 3]] = tot;
    }
    f.clear();
    for(int i = 1 ; i <= 2 * N ; ++i) {
        if(!ans[i]) f.pb(i);
    }
    siz = f.size();
    for(int i = 0 ; i < siz ; i += 2) {
        ans[f[i]] = ++tot;ans[f[i + 1]] = tot;
    }
    for(int i = 1 ; i <= 2 * N ; ++i) {out(ans[i]);space;}
    enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

H - Generalized Insertion Sort

爲了調這題我特地寫了spj,而後發現我數組開小了

簡直zz

刷atcoder真是鍛鍊了我寫spj的能力QAQ

咱們考慮把全部從葉子開始的一條鏈挑出來,每次處理它們並刪掉,這樣只有logn層,由於最多的狀況就是一個滿二叉樹

而後咱們若是有一個紅點來到根,它所在的底部鏈有一個紅點序列,咱們相似插入排序把它插入該到的地方

若是有一個白點,咱們把它扔到深度最大的地方,且沒有排序過的紅點,並標稱黑點

可是黑點有可能被頂上去,咱們發現黑點被頂上去只多是放了一個紅點,因此複雜度均攤下來就是\(n \log n + n\)

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define MAXN 4005
#define mo 974711
//#define ivorysi
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 + 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,fa[MAXN],son[MAXN];
vector<int> ne[MAXN];
int a[MAXN],pos[MAXN];
int que[MAXN],tot,pre[MAXN],red,bot[MAXN];
bool vis[MAXN],cov[MAXN],bl[MAXN];
int ans[25005],q;
void drag(int v) {
    if(v == 0) return;
    ans[++q] = v;
    int u = v;
    int t = a[u];
    while(fa[u] != -1) {
    int k = a[fa[u]];
    a[fa[u]] = t;
    pos[t] = fa[u];
    t = k;
    u = fa[u];
    }
    a[v] = t;pos[t] = v;
}
void Process() {
    while(red) {
    if(vis[a[0]]) {
        int u = bot[a[0]];
        //while(u != -1 && u == a[u]) {cov[u] = 1;u = fa[u];}
        while(1) {
        if(!cov[u] || a[u] < a[0]) break;
        u = fa[u];
        }
        drag(u);
        while(cov[u]) u = fa[u];
        cov[u] = 1;
        --red;
    }
    else {
        for(int i = N - 1 ; i >= 0 ; --i) {
        if(!cov[i] && !bl[a[i]]) {
            bl[a[0]] = 1;
            drag(i);break;
        }
        }
    }
    }
}
void Solve() {
    read(N);
    fa[0] = -1;
    for(int i = 1 ; i < N ; ++i) {
    read(fa[i]);son[fa[i]]++;
    ne[fa[i]].pb(i);
    }
    for(int i = 0 ; i < N ; ++i) {
    read(a[i]);
    pos[a[i]] = i;
    }
    while(1) {
    tot = 0;
    memset(pre,0,sizeof(pre));
    memset(bl,0,sizeof(bl));
    memset(bot,0,sizeof(bot));
    red = 0;
    for(int i = N - 1 ; i >= 0 ; --i) {
        if(!vis[i]) {
        if(!son[i] || (son[i] == 1 && pre[i])) {
            que[++tot] = i;
            if(fa[i] != -1 && son[fa[i]] == 1) pre[fa[i]] = i;
            if(pre[i]) bot[i] = bot[pre[i]];
            else bot[i] = i;
            vis[i] = 1;
            ++red;
        }
        }
    }
    if(!red) break;
    Process();
    for(int i = 1 ; i <= tot ; ++i) {
        --son[fa[que[i]]];
    }
    }
    out(q);enter;
    for(int i = 1 ; i <= q ; ++i) {
    out(ans[i]);enter;
    }
}

int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

I - Simple APSP Problem

一開始想到離散化以後各類分類討論,瞬間不可寫了QAQ

最後就瞭解了一下簡便的寫法

就是對於兩個相鄰的空行,咱們把跨過它的貢獻統計出來,把它縮成一行,列也同樣,這樣一個點內之間的路徑長度都是0

這樣就變成了\(2n * 2n\)的一個矩形,每一個矩形裏面有一個值表明這個點原來方塊的大小

而後對於每一個點用BFS跑最短路,兩兩枚舉點對加上便可

代碼

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 1000005
//#define ivorysi
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 + 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 H,W,N;
int x[35],y[35];
int sum[MAXN],a[MAXN],nxtr[MAXN],nxtc[MAXN];
int pos[MAXN],ans;
int g[65][65],r,c,f[65][65];
bool vis[65][65];
int dx[] = {0,-1,0,1},dy[] = {1,0,-1,0};

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,int y) {
    x = inc(x,y);
}
queue<pii > Q;
void BFS(int x,int y) {
    memset(vis,0,sizeof(vis));
    vis[x][y] = 1;f[x][y] = 0;
    Q.push(mp(x,y));
    while(!Q.empty()) {
    pii t = Q.front();Q.pop();
    for(int k = 0 ; k < 4 ; ++k) {
        int mx = t.fi + dx[k],my = t.se + dy[k];
        if(mx >= 1 && mx <= r && my >= 1 && my <= c) {
        if(!vis[mx][my] && g[mx][my] != -1) {
            f[mx][my] = f[t.fi][t.se] + 1;
            Q.push(mp(mx,my));
            vis[mx][my] = 1;
        }
        }
    }
    }
}
void Solve() {
    read(H);read(W);
    read(N);
    for(int i = 1 ; i <= N ; ++i) {
    read(x[i]);read(y[i]);
    ++x[i];++y[i];
    }
    for(int i = 1 ; i <= H ; ++i) a[i] = W;
    a[H + 1] = 0;
    for(int i = 1 ; i <= N ; ++i) --a[x[i]];
    for(int i = 1 ; i <= H ; ++i) {
    sum[i] = inc(sum[i - 1],a[i]);
    }
    memset(pos,0,sizeof(pos));
    for(int i = 1 ; i <= H ; ++i) pos[i] = i;
    for(int i = 1 ; i <= H ; ++i) {
    if(a[i] == W && a[i + 1] == W) {
        update(ans,mul(sum[i],inc(sum[H],MOD - sum[i])));
        pos[i + 1] = pos[i];
        nxtr[pos[i]] = i + 2;
    }
    else nxtr[pos[i]] = i + 1;
    }
    for(int i = 1 ; i <= W ; ++i) a[i] = H;
    a[W + 1] = 0;
    for(int i = 1 ; i <= N ; ++i) a[y[i]]--;
    for(int i = 1 ; i <= W ; ++i) sum[i] = inc(sum[i - 1],a[i]);
    memset(pos,0,sizeof(pos));
    for(int i = 1 ; i <= W ; ++i) pos[i] = i;
    for(int i = 1 ; i <= W ; ++i) {
    if(a[i] == H && a[i + 1] == H) {
        update(ans,mul(sum[i],inc(sum[W],MOD - sum[i])));
        pos[i + 1] = pos[i];
        nxtc[pos[i]] = i + 2;
    }
    else nxtc[pos[i]] = i + 1;
    }
    int tmp = 1;
    while(tmp != H + 1) {tmp = nxtr[tmp];++r;}
    tmp = 1;
    while(tmp != W + 1) {tmp = nxtc[tmp];++c;}
    int p1 = 1;
    for(int i = 1 ; i <= r ; ++i) {
    int p2 = 1;
    for(int j = 1 ; j <= c ; ++j) {
        g[i][j] = mul(nxtr[p1] - p1,nxtc[p2] - p2);
        if(nxtr[p1] - p1 == 1 && nxtc[p2] - p2 == 1) {
        for(int k = 1 ; k <= N ; ++k) {
            if(x[k] == p1 && y[k] == p2) {
            g[i][j] = -1;
            break;
            }
        }
        }
        p2 = nxtc[p2];
    }
    p1 = nxtr[p1];
    }
    tmp = 0;
    for(int i = 1 ; i <= r ; ++i) {
    for(int j = 1 ; j <= c ; ++j) {
        if(g[i][j] != -1) {
        BFS(i,j);
        for(int k = 1 ; k <= r ; ++k) {
            for(int h = 1 ; h <= c ; ++h) {
            if(g[k][h] != -1) update(tmp,mul(f[k][h],mul(g[i][j],g[k][h])));
            }
        }
        }
    }
    }
    tmp = mul(tmp,(MOD + 1) / 2);
    update(ans,tmp);
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

J - Rectangles

神仙數數題呀QAQ

計算出至少有一維是對齊的方案數,能夠用容斥
至少一維對齊-至少兩維對齊 + 至少三維對齊

而後計算每一維都不對齊的方案數

對於\(p + i,r + j,q + k\)這個點標上\(k\)
那麼對於前兩維,我對於\(v(x,y,z)\)從下往上必定能夠獲得一個0,1,2,3,4...c-1,0,1,2,3,4..c - 1的的循環同構串

那麼我對於最底層的平面,顯然這是一個填滿了數的矩形,咱們要把它劃分紅\(a*b\)的矩形,使得每一個矩形裏數字都同樣,問方案數

若是有一行或一列錯開了,且這行這列填的數互不相同,那這種狀況必定是某一維對齊的狀況

因此咱們的要填的矩形應該是一個正好被劃分紅了\(\frac{A*B}{a*b}\)個小矩形
這個時候有一個高度\(h\),它至少佔有了一行一列,而後至少在某一層,它移動了某一行,至少在另外一層,它動了某一列
且這個高度\(h\)只有一個

咱們記佔有的行數爲\(p\),列數爲\(q\),方案數是\((a^q + b^p - 1)^{C / c} - (a^q)^{C / c} - (b^p)^{C / c} + 1\)

而後剩下的要求這種顏色填不成新的行和列,用容斥一下就行,至少零行同樣 - 至少一行同樣+ 至少兩行同樣-至少三行同樣
列不一同樣能夠用\(c^{i} - 1\)來限制

代碼

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 1000005
//#define ivorysi
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 + 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 A,B,C,a,b,c;
int ans;
int binom[105][105],f[105][105],g[105][105];
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 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;
}
int Calc(int a,int A,int b,int B) {
    int res = 0;
    update(res,mul(b,fpow(a,B / b)));
    update(res,mul(a,fpow(b,A / a)));
    update(res,MOD - mul(a,b));
    return res;
}
void Trivial() {
    update(ans,mul(c,fpow(Calc(a,A,b,B),C / c)));
    update(ans,mul(b,fpow(Calc(a,A,c,C),B / b)));
    update(ans,mul(a,fpow(Calc(b,B,c,C),A / a)));
    update(ans,MOD - mul(mul(b,c),fpow(a,B / b * C / c)));
    update(ans,MOD - mul(mul(a,c),fpow(b,A / a * C / c)));
    update(ans,MOD - mul(mul(a,b),fpow(c,A / a * B / b)));
    update(ans,mul(mul(a,b),c));
    
}
void Solve() {
    Trivial();
    binom[0][0] = 1;
    for(int i = 1 ; i <= 100 ; ++i) {
    binom[i][0] = 1;
    for(int j = 1 ; j <= i ; ++j) {
        binom[i][j] = inc(binom[i - 1][j - 1],binom[i - 1][j]);
    }
    }
    for(int i = 0 ; i <= A / a ; ++i) {
    for(int j = 0 ; j <= B / b ; ++j) {
        int t = 1;
        for(int k = 0 ; k <= i ; ++k) {
        int tmp = inc(fpow(c,i - k),MOD - 1);
        tmp = fpow(tmp,j);
        update(g[i][j],mul(mul(tmp,binom[i][k]),t));
        t = mul(t,MOD - 1);
        }
    }
    }
    int all = 0;
    for(int i = 1 ; i <= A / a ; ++i) {
    for(int j = 1 ; j <= B / b ; ++j) {
        if(i == A / a && j == B / b) continue;
        int k = fpow(a,j),t = fpow(b,i);
        update(f[i][j],fpow(inc(inc(k,t),MOD - 1),C / c));
        update(f[i][j],MOD - fpow(k,C / c));
        update(f[i][j],MOD - fpow(t,C / c));
        update(f[i][j],1);
        int tmp = mul(f[i][j],mul(binom[A / a][i],binom[B / b][j]));
        tmp = mul(tmp,c);
        tmp = mul(tmp,g[A / a - i][B / b - j]);
        update(all,tmp);
    }
    }
    all = mul(all,mul(a,b));
    update(ans,all);
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    read(a);read(b);read(c);read(A);read(B);read(C);
    if(A % a == 0 && B % b == 0 && C % c == 0) Solve();
    else puts("0");
    return 0;
}
相關文章
相關標籤/搜索