【AtCoder】AGC023 AF Problem Solution

It can be said that it is the first AGC. After doing three questions, there are still 30 minutes. I checked the D question and found that I couldn’t come out. The three questions were rough and the
rating started at 1300+, which still feels very good. . .
Only the level of three questions will obviously go crazy in the future - ah (the painful experience of CF)

The feeling of changing the question seems to be good because the thinking is very wonderful (I can't think of it at all)

A - Zero-Sum Ranges

For everyone's small water problem, the sum of the interval is 0. Sum[R] == sum[L - 1], just record how many times the sum of a certain value appears, if you are too lazy to discretize and use map directly OK

code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#define MAXN 200005
#define PLI pair<long long,int>
#define fi first
#define se second
#define mp make_pair
//#define ivorysi
using namespace std;
typedef long long int64;
int N;
int64 A[MAXN];
map<int64,int> mmm;
void Solve() {
    scanf("%d",&N);
    for(int i = 1 ; i <= N ; ++i) scanf("%lld",&A[i]);
    mmm[0] = 1;
    int64 ans = 0;
    for(int i = 1 ; i <= N ; ++i) {
        A[i] += A[i - 1];
        ans += mmm[A[i]];
        mmm[A[i]] += 1;
    }
    printf("%lld\n",ans);
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
    return 0;
}

B - Find Symmetries

After the matrix row is circularly shifted by x and the column is circularly shifted by y, the matrix is ​​symmetrical about the diagonal line from the upper left to the lower right. The
matrix size is 300.
Then I wrote a violence, but I did not find that my violence is \(n^4 \) Then happy TLE
, I started to think about optimization, and found that fixed row translation, the change of the hash value of each translation column can be calculated by O1, check compares the hash of each row and column, it is O(n), and then passed

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#define MAXN 200005
#define PLI pair<long long,int>
#define fi first
#define se second
#define mp make_pair
#define ha 99994711
#define ba 823
//#define ivorysi
using namespace std;
typedef long long int64;
int N;
char s[305][305],b[305][305];
int64 hc[305],hr[305],e;
inline int C(int x) {
    return x > N ? x - N : x;
}
bool check(int y) {
    int T = C(N + y);
    for(int i = 1 ; i <= N ; ++i) 
        hr[i] = (hr[i] * ba + (b[i][T] - 'a' + 1)) % ha;
    for(int i = 1 ; i <= N ; ++i) {
        if(hr[i] != hc[C(i + y)]) {
            T = C(N + y + 1);
            for(int j = 1 ; j <= N ; ++j) 
                hr[j] = (hr[j] - e * (b[j][T] - 'a' + 1) % ha + ha) % ha;
            return false;
        }
    }
    T = C(N + y + 1);
    for(int i = 1 ; i <= N ; ++i) 
        hr[i] = (hr[i] - e * (b[i][T] - 'a' + 1) % ha + ha) % ha;
    return true;
}
void Solve() {
    scanf("%d",&N);
    if(N == 1) {
        puts("1");return;
    }
    e = 1;
    for(int i = 1 ; i < N ; ++i) e = e * ba % ha;
    for(int i = 1 ; i <= N ; ++i) {
        scanf("%s",s[i] + 1);
    }
    int cnt = 0;
    for(int A = 0 ; A < N ; ++A) {
        memset(hc,0,sizeof(hc));
        memset(hr,0,sizeof(hr));
        for(int i = 1 ; i <= N ; ++i) {
            for(int j = 1 ; j <= N ; ++j) {
                b[i][j] = s[C(i + A)][j];
                hc[j] = (hc[j] * ba + (b[i][j] - 'a' + 1)) % ha;
                if(j != N) {
                    hr[i] = (hr[i] * ba + (b[i][j] - 'a' + 1)) % ha;
                }
            }
        }
        for(int B = 0 ; B < N ; ++B) {
            if(check(B)) ++cnt;
        }
    }
    printf("%d\n",cnt);
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
    return 0;
}

C - Painting Machines

while(1) push formula Think
of Gensokyo after the earthquake. Obviously, the title can be transformed into
\(\sum_{i = 0}^{N - 2} T(i)\) where \(T(i)\) means There are \(T(0) = (N - 1)!\) The number of solutions that
have not been completely blacked after using i operations is \(T(0) = (N - 1)!\)
and then classified and discussed. One is that the number of solutions that are not fully blacked because N-1 is not used is \ (\binom{N - 2}{i}i!\)
If N - 1 is used, then the solution is \((\binom{N - 2}{i - 1} - W(i - 1))i! \)
\(W(i)\) Indicates the number of solutions that use a machine N - 1 and other i machines to blacken all squares.
Obviously, there will be 1
sequence difference in the sequence, and you will find this sequence Either 1 or 2, that is, the number of a pile of 1 and a pile of 2 is fixed, the sum of a pile of 1 and a pile of 2 is N - 2, this is a binary equation, and then the number of 1 and the number of 2 are calculated. The number is a full arrangement with repeated elements. The answer is
\(\frac{(num_1 + num_2)! }{num_1 ! num_2 !}\)
other \(N - 1 - i\) machines are randomly arranged, and finally Also multiply by \((N - i - 1)!\)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#define MAXN 1000005
#define PLI pair<long long,int>
#define fi first
#define se second
#define mp make_pair
#define ha 99994711
#define ba 823
#define MOD 1000000007
//#define ivorysi
using namespace std;
typedef long long int64;
int64 fac[MAXN],invfac[MAXN],ans;
int N;
int64 fpow(int64 x,int64 c) {
    int64 res = 1,t = x;
    while(c) {
        if(c & 1) res = res * t % MOD;
        t = t * t % MOD;
        c >>= 1;
    }
    return res;
}
int64 C(int n,int m) {
    if(n < m) return 0;
    return fac[n] * invfac[m] % MOD * invfac[n - m] % MOD;
}
int64 W(int k) {
    int x = N - 2 - k;
    int y = k - x;
    if(x < 0 || y < 0) return 0;
    return fac[k] * invfac[y] % MOD * invfac[x] % MOD;
}
void Solve() {
    scanf("%d",&N);
    if(N == 2) {
        puts("1");
        return;
    }
    fac[0] = invfac[0] = 1;
    for(int i = 1 ; i <= N ; ++i) {
        fac[i] = fac[i - 1] * i % MOD;
    }
    invfac[N] = fpow(fac[N],MOD - 2);
    for(int i = N - 1 ; i >= 1 ; --i) {
        invfac[i] = invfac[i + 1] * (i + 1) % MOD;
    }
    ans += fac[N - 1];
    for(int i = 1 ; i < N - 1 ; ++i) {
        ans += (C(N - 2,i) + C(N - 2,i - 1) + MOD - W(i - 1))* fac[i] % MOD * fac[N - 1 - i] % MOD;
        ans %= MOD;
    }
    printf("%lld\n",ans);
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
    return 0;
}

D - Go Home

answer

The fairy game question (actually not a game)
after reading the question, you will find, what is the best decision, what is the best, what is the best, what is the best thing, give it up...
The solution says so, if the car is in 1 and N are between, and \(A_1 >= A_n\) , then N will definitely vote for 1, why, because you can't win, if you let the car close to N temporarily, it will also be because everyone in the N - 1 apartment will return The car returns to 1 again after home, so in order to go home early, N’s ticket will be given 1, and the last operation must have a length of \(X_{n} - X_{1}\) , then we put N's votes are all given to 1, and \(P_{1} += P_{N}\) is no problem. If \(A_{n} > A_{1}\) is similar, then it becomes 1 and Sub-problems between N - 1... The stopping condition is that all apartments are on one side of the initial position \(S\)
. If the answer is accumulated, pay attention to the opposite direction of the previous operation, if the previous 1 - N, the next 1 - (N - 1), the second distance does not need to be added to the answer

code

#include <iostream>
#include <cstdio>
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
int N;
int64 S,X[MAXN],P[MAXN],ans;
void Solve() {
    scanf("%d%lld",&N,&S);
    for(int i = 1 ; i <= N ; ++i) {
        scanf("%lld%lld",&X[i],&P[i]);
    }
    int L = 1,R = N;
    int dir = 0;
    while(1) {
        if(X[L] >= S) {ans += X[R] - S;break;}
        if(X[R] <= S) {ans += S - X[L];break;}
        if(P[L] >= P[R]) {
            if(dir != 1) {dir = 1;ans += X[R] - X[L];}
            P[L] += P[R];R--;
        }
        else {
            if(dir != 2) {dir = 2;ans += X[R] - X[L];}
            P[R] += P[L];L++;
        } 
    }
    printf("%lld\n",ans);
}
 
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
    return 0;
}

E - Inversions

I think the method of calculating the arrangement of this question should be regarded as a relatively important prerequisite skill, but this is not a board or something. If you know this sub-problem, then this question will at least have a clue
how to calculate the restricted arrangement of each digit. The total number of?
First calculate a \(cnt[k]\) to indicate the number of positions that can be filled with k, which can be calculated with a suffix and the
answer is \(\prod_{i = 1}^{N} cnt[i] - (N - i)\)
With this, let's look at this question again. We calculate the \(i\) position
for two positions \(i < j\) and \(A_{i} <= A_{j}\) The number is greater than the sum of the permutations of the numbers at the position of \(j\) , we can let \(A_{j} = A_{i}\) , then calculate the number of permutations, and then divide by two is the answer The following \(cnt[ i]\) is changed to \(cnt[i] - (N - i)\) so that we consider changing \(A_{j}\) to make \([A_{i} + 1,A_{j}] \) The cnt of this interval is subtracted by 1, that is, it is multiplied by \((cnt[i] - 1) / cnt[i]\)

, that is, it is processed into an interval prefix product and then divided. However, it will be found that the case of processing 0 is special, and it is necessary to record a few 0s in the prefix, and the number of 0s on the prefix is ​​the same value is not 0, and the number of 0s is increased in the position. Monotonic does not decrease, so the start position and end position of each segment can be preprocessed
\(A_{i} > A_{j}\) We found that the total arrangement after \(A_{i} := A_{j}\) The number minus half of the calculated new permutation value
Both of the above can be quickly maintained with a tree array

code

#include <iostream>
#include <cstdio>
#include <cstring>
#define MAXN 200005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
const int MOD = 1000000007;
int N,A[MAXN],x[MAXN],st[MAXN],ed[MAXN];
int64 cnt[MAXN],V[MAXN],D[MAXN],ID[MAXN],S,tr[MAXN],tr_cnt[MAXN],Inv_2,ans;
int64 fpow(int64 x,int64 c) {
    int64 res = 1,t = x;
    while(c) {
        if(c & 1) res = res * t % MOD;
        t = t * t % MOD;
        c >>= 1;
    }
    return res;
}
int lowbit(int x) {return x & (-x);}
void insert(int x,int64 v) {
    while(x <= N) {
        tr[x] += v;
        tr[x] %= MOD;
        tr_cnt[x]++;
        x += lowbit(x);
    }
}
int64 Query(int x,int64 v) {
    int64 res = 0;
    while(x > 0) {
        res += tr[x];
        x -= lowbit(x);
    }
    res %= MOD;
    return res * v % MOD;
}
int64 getnum(int x) {
    int64 res = 0;
    while(x > 0) {
        res += tr_cnt[x];
        x -= lowbit(x);
    }
    return res;
}
int64 Query_range(int L,int R,int64 v) {
    if(L == 0) ++L;
    if(L > R) return 0;
    return (Query(R,v) + MOD - Query(L - 1,v)) % MOD;
}
void Solve() {
    scanf("%d",&N);
    for(int i = 1 ; i <= N ; ++i) scanf("%d",&A[i]),cnt[A[i]]++;
    for(int i = N - 1; i >= 1 ; --i) cnt[i] += cnt[i + 1];
    S = 1;Inv_2 = (MOD + 1) / 2;
    for(int i = 1 ; i <= N ; ++i) {
        cnt[i] -= N - i;
        if(cnt[i] <= 0) {puts("0");return;}
        S = S * cnt[i] % MOD;
    }
    for(int i = 1 ; i <= N ; ++i) {
        V[i] = (cnt[i] - 1) * fpow(cnt[i],MOD - 2) % MOD;
    }
    D[0] = 1;
    st[0] = 0;
    for(int i = 1 ; i <= N ; ++i) {
        x[i] = x[i - 1];D[i] = D[i - 1];
        if(V[i] == 0) {x[i]++;st[x[i]] = i;ed[x[i] - 1] = i - 1;}
        else D[i] = D[i] * V[i] % MOD;
        ID[i] = fpow(D[i],MOD - 2);
    }
    ed[x[N]] = N;
    for(int i = 1 ; i <= N ; ++i) {
        ans += Query_range(st[x[A[i]]],A[i],D[A[i]] * S % MOD * Inv_2 % MOD);
        ans %= MOD;
        insert(A[i],ID[A[i]]);
    }
    memset(tr,0,sizeof(tr));
    memset(tr_cnt,0,sizeof(tr_cnt));
    for(int i = 1 ; i <= N ; ++i) {
        int64 t = Query_range(A[i] + 1,ed[x[A[i]]],ID[A[i]] * S % MOD * Inv_2 % MOD);
        ans += ((getnum(N) - getnum(A[i])) * S % MOD + MOD - t) % MOD;
        ans %= MOD;
        insert(A[i],D[A[i]]);
    }
    printf("%lld\n",ans);
}
 
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
    return 0;
}

F - 01 on Tree

answer

This is a real fairytale. . .
The mind has always been greedy according to the size of the subtree, and then it has been forked off.
Finally, it is said that each node is initialized as a separate tree, and the number of 1s and 0s in this tree is recorded. Initially, the number of 1s is Whether the node value is 1, the number of 0 is whether the node value is 0.
We sort according to \(C_{0i}/C_{1i}\) , and connect each point with the direct parent, which means to put this The 0 and 1 of the point are connected to the back of the father node, and the extra contribution is that
v is the son and p is the father. \(C_{1p} * C_{0v}\)
Push the formula to prove that another son is selected It is definitely not good
, and then update the value of the father p, that is, p becomes a new tree, which can be maintained with a union lookup,
and then the updated sorting can be implemented with a set

Fairy Topic Fairy Topic. . .

code

#include <iostream>
#include <cstdio>
#include <vector>
#include <set>
#include <cstring>
#define MAXN 200005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
int N,P[MAXN],V[MAXN],fa[MAXN],C[2][MAXN];
int getfa(int x) {
    return fa[x] == x ? x : fa[x] = getfa(fa[x]);
}
struct cmp {
    bool operator() (const int &a,const int &b) {
        if(1LL * C[0][a] * C[1][b] != 1LL * C[0][b] * C[1][a])
            return 1LL * C[0][a] * C[1][b] > 1LL * C[0][b] * C[1][a];
        else return a > b;
    }
};
multiset<int,cmp> S;
void Solve() {
    scanf("%d",&N);
    for(int i = 2 ; i <= N ; ++i) scanf("%d",&P[i]);
    for(int i = 1 ; i <= N ; ++i) scanf("%d",&V[i]);
    for(int i = 1 ; i <= N ; ++i) fa[i] = i;
    for(int i = 1 ; i <= N ; ++i) C[V[i]][i] = 1;
    for(int i = 2 ; i <= N ; ++i) S.insert(i);
    int64 ans = 0;
    for(int i = 1 ; i <= N - 1 ; ++i) {
        int v = *S.begin();
        int p = getfa(P[v]);
        S.erase(v);S.erase(p);
        ans += 1LL * C[0][v] * C[1][p];
        C[1][p] += C[1][v];C[0][p] += C[0][v];
        fa[v] = p;
        if(p != 1) S.insert(p);
    }
    printf("%lld\n",ans);   
}
 
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
    return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325310676&siteId=291194637