2019 Nanchang (Revisiting Classics)

Introduction

It's very difficult. I'm aware of the gap in knowledge points again

Knowledge points involved

Shape pressure DP, thinking, combinatorial mathematics, DSU on Tree, line segment tree

Link: 2019 Nanchang Regional

subject

C

Give a large nonnegative integer n n n. Calculate integer pairs that meet the following conditions ( i , j ) (i,j) (i,j), n n n is given in binary form

  1. 0 ≤ j ≤ i ≤ n 0\le j\le i\le n 0≤j≤i≤n
  2. i & n = i i \&n=i i&n=i
  3. i & j = 0 i\& j=0 i&j=0

Train of thought: it is constructed according to the problem setting conditions i i i only in n n The 1 bit of n corresponds to a value, and j j j is not greater than i i Under the premise of i, the value of each bit is arbitrary, in order to ensure i i i greater than j j j. In construction i i i is constructed in sequence from low to high. Assuming that the current bit of i is fixed to 1 and the other high bits are fixed to 0, discuss the low bit by category, that is, similar to 000001xxxxx, assuming that it is the penultimate p p p-bit, n n n this bit corresponds to 1, reciprocal 1 − p 1-p 1 − p bit in total k k k 1, m m m zeros, then the total number of schemes can be obtained as:

C k 0 2 m + k + C k 1 2 m + k − 1 + ⋯ + C k k 2 m C_k^02^{m+k}+C_k^12^{m+k-1}+\dots+C_k^k2^m Ck0​2m+k+Ck1​2m+k−1+⋯+Ckk​2m
= 2 m ( C k 0 2 k + C k 1 2 k − 1 + ⋯ + C k k ) =2^m(C_k^02^k+C_k^12^{k-1}+\dots+C_k^k) =2m(Ck0​2k+Ck1​2k−1+⋯+Ckk​)
= 2 m ( C k k 2 k + C k k − 1 2 k − 1 + ⋯ + C k 0 2 0 ) =2^m(C_k^k2^k+C_k^{k-1}2^{k-1}+\dots+C_k^02^0) =2m(Ckk​2k+Ckk−1​2k−1+⋯+Ck0​20)

Therefore, the formula can be deduced, but obviously the formula is more complex and can be further simplified

Known ( 1 + x ) n = C n 0 x 0 + C n 1 x 1 + ... C n n x n (1+x)^n=C_n^0x^0+C_n^1x^1+\dots C_n^nx^n (1+x)n=Cn0​x0+Cn1​x1+...Cnn​xn
take x = 2 x=2 x=2
( 1 + 2 ) n = C n 0 2 0 + C n 1 2 1 + ... C n n 2 n (1+2)^n=C_n^02^0+C_n^12^1+\dots C_n^n2^n (1+2)n=Cn0​20+Cn1​21+...Cnn​2n

Therefore, the final formula can be deduced as 2 m 3 k 2^m3^k 2m3k

code

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define int long long
using namespace std;
const int maxn=1e5+5;
const int mod=1e9+7;
int T;
char s[maxn];
int qpow(int power,int base) {
    int result=1;
    while(power) {
        if(power&1)
            result=result*base%mod;
        power>>=1;
        base=base*base%mod;
    }
    return result%mod;
}
signed main() {
    scanf("%lld",&T);
    while(T--) {
        scanf("%s",s+1);
        int len=strlen(s+1),cnt=0,res=0;
        for(int i=len; i>=1; i--)
            if(s[i]=='1') {
                res=(res+(qpow(cnt,3)*qpow(len-i-cnt,2))%mod)%mod;
                cnt++;
            }
        res=(res+1)%mod;//Plus i=j=0
        printf("%lld\n",res);
    }
    return 0;
}

E

General idea of the title: give a n n Undirected graph of n nodes, with m m m weighted edges, each of which is either black or white. Now we need to select some edges to construct a new graph so that the graph is connected, and we can only select no more than k k k white edges, find the sum of the maximum edge weights that can be obtained by the new graph. If the new graph cannot be connected, output - 1

Idea: first select all the black edges, then mark them with the union search set, then sort the white edges from large to small, traverse the white edges, select the white edges on the premise of ensuring connectivity, and select the white edges with large edge weight if there are more times

code

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define int long long
using namespace std;
const int maxn=5e5+5;
int T,n,m,k,f[maxn];
bool vis[maxn];
int Seek(int x) {//Path compression
    if(x==f[x])return x;
    return f[x]=Seek(f[x]);
}
void Union(int x,int y) {//merge
    int fx=Seek(x),fy=Seek(y);
    if(fx!=fy)f[fx]=fy;
}
struct node {//Overload ratio size
    int from,to,w;
    bool operator<(const node &a)const {
        return w>a.w;
    }
} e[maxn];
signed main() {
    scanf("%lld",&T);
    while(T--) {
        scanf("%lld%lld%lld",&n,&m,&k);
        memset(vis,0,sizeof(vis));//initialization
        int sum=0,cnt=0;
        bool flag=0;
        for(int i=1; i<=n; i++)f[i]=i;
        while(m--) {
            int u,v,w,c;
            scanf("%lld%lld%lld%lld",&u,&v,&w,&c);
            if(c) {//White edge needs to be entered
                e[++cnt].from=u;
                e[cnt].to=v;
                e[cnt].w=w;
            } else {//Direct use of black edges
                if(Seek(u)!=Seek(v))
                    Union(u,v);
                sum+=w;
            }
        }
        sort(e+1,e+1+cnt);//sort
        for(int i=1; i<=cnt&&k; i++) {//Traverse all the white edges and ensure connectivity first
            int u=e[i].from,v=e[i].to;
            if(Seek(u)!=Seek(v)) {
                Union(u,v);
                k--;
                sum+=e[i].w;
                vis[i]=1;
            }
        }
        for(int i=1; i<=n; i++)
            if(Seek(i)!=Seek(1)) {
                flag=1;
                break;
            }
        if(flag) {
            printf("-1\n");
            continue;
        }
        for(int i=1; i<=cnt&&k; i++)
            if(vis[i])continue;
            else {
                k--;
                sum+=e[i].w;
            }
        printf("%lld\n",sum);
    }
    return 0;
}

G

Main idea of the title: omitted

Idea: first of all, the module given in the topic is a composite number, and the maximum prime factor is 2803. Then, the factorial corresponding to the value greater than 2803 will inevitably result in 0. Only the numbers in the range of 1 ~ 2803 need to be considered, so only violence is needed O ( n 2 ) O(n^2) O(n2) traverse all intervals, judge the maximum value that can be reached by different interval sizes, and finally find the corresponding answer according to the input (note that the larger the interval is, the larger the value will be)

code

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define int long long
using namespace std;
const int maxn=1e5+5;
const int mod=998857459;
int n,m,a[maxn],mul[maxn]= {1},cnt,sum[3000],ans[maxn];
struct node {
    int val,id;
} res[3000];
signed main() {
    scanf("%lld%lld",&n,&m);
    for(int i=1; i<2803; i++)//Preprocessing factorial
        mul[i]=(mul[i-1]*i)%mod;
    for(int i=1; i<=n; i++) {
        int x;
        scanf("%lld",&x);
        a[i]=mul[x];//Record results
    }
    for(int i=1; i<=n; i++)
        if(a[i]) {//Re record results
            res[++cnt].val=a[i];
            res[cnt].id=i;
            sum[cnt]=sum[cnt-1]+res[cnt].val%mod;//Prefix and
        }
    for(int i=1; i<=cnt; i++)
        for(int j=i; j<=cnt; j++)//Try different ranges
            ans[res[j].id-res[i].id+1]=max(ans[res[j].id-res[i].id+1],(sum[j]-sum[i-1]+mod)%mod);
    while(m--) {
        int x,len=INF;
        scanf("%lld",&x);
        for(int i=1; i<=n; i++)
            if(ans[i]>=x) {
                len=i;
                break;
            }
        if(len==INF)printf("-1\n");
        else printf("%lld\n",len);
    }
    return 0;
}

L

Main idea of the title: Yes n n n football teams take part in the game, and each team will compete with the rest n − 1 n-1 n − 1 team will play one game each. Now the results of all games will be given to judge whether there is a champion. If there is an output number, otherwise the corresponding string will be output. The winner of each game will get 3 points and each draw will get 1 point. The champion is the team with the largest score and the largest number of net goals (net goals = goals - goals lost)

Idea: directly count the violence, and finally rank according to the requirements of the topic and give a special judgment 1

code

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define int long long
using namespace std;
const int maxn=1e3+50;
int n,match[121][121];
struct node {
    int get,score,id;
    bool operator<(const node& a)const {
        if(score==a.score)return get>a.get;
        return score>a.score;
    }
} team[121];
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >>n;
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=n; j++)
            cin >>match[i][j];
        team[i].id=i;
    }
    if(n==1) {
        cout <<1;
        return 0;
    }
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)//It's actually heavy here, but the relative size remains the same, which doesn't affect it
            if(i!=j) {
                team[i].get+=match[i][j];
                team[i].get-=match[j][i];
                team[j].get+=match[j][i];
                team[j].get-=match[i][j];
                if(match[i][j]>match[j][i])team[i].score+=3;
                else if(match[i][j]==match[j][i])team[i].score++,team[j].score++;
                else team[j].score+=3;
            }
    sort(team+1,team+1+n);
    if(team[1].score==team[2].score&&team[1].get==team[2].get)cout <<"play-offs";
    else cout <<team[1].id;
    return 0;
}

reference

  1. 2019ICPC Nanchang C And and Pair dp (binomial theorem / dp)
  2. 2019 ICPC Nanchang regional competition - G Eating Plan (skill + violence)

Keywords: Algorithm Dynamic Programming

Added by jrodd32 on Mon, 14 Feb 2022 12:17:41 +0200