2022 TZC training team provincial competition trial 1 problem solution

Posted by lemist on Sun, 06 Mar 2022 13:03:29 +0100

A(*) enumeration

The title means to find

  • The logarithm of the largest adjacent difference
    • If the difference is the same, select the one with the highest height
      • If the height is the same, select the number with the largest number
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 110;
int w[N],n;
int res=2;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&w[i]);
    for(int i=2;i<=n;i++){
        if(abs(w[i]-w[i-1])>abs(w[res]-w[res-1])){
            res=i;
        }
        else if(abs(w[i]-w[i-1])==abs(w[res]-w[res-1])){
            if(max(w[i],w[i-1])>=max(w[res],w[res-1]))res=i;
        }
    }
    printf("%d %d\n",res-1,res);
    return 0;
}

C(*) structure Sorting

Sort the average value of each string. In order to prevent accuracy problems, replace / with*

#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
map<string,int>mp;
int idx=0;
struct aa{
    string s;
    int sum,cnt;
    bool operator <(const aa &c)const{
        return (ll)sum*c.cnt<(ll)c.sum*cnt;
    }
}w[510];
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        string s;
        cin>>s;
        if(!mp.count(s)){
            ++idx;mp[s]=idx;
            w[idx]={s,i,1};
        }
        else{
            int c=mp[s];
            w[c].sum+=i;
            w[c].cnt++;
        }
    }
    sort(w+1,w+1+idx);
    for(int i=1;i<=idx;i++)cout<<w[i].s<<endl;
    return 0;
}

Preorder traversal and postorder traversal of H(* *) tree

Store the number of each traversal into the array
For a number id, it corresponds to a weight

  • When c[idx] is 0 - > x - y remains unchanged
  • When c[idx] is 1
    • Number of pre sequence traversal position > number of post sequence traversal position - > x - y increase
    • The number of pre sequence traversal position < the number of post sequence traversal position - > x - y decrease
      All enumerations can be completed by each number
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int N = 1e5+5,mod=998244353;
vector<int>da,db;
ll d[N];
int s1[N],s2[N];
struct aa{
    int l,r;
}tr[N];
void dfs_front(int u){
    if(!u)return ;
    da.push_back(u);
    dfs_front(tr[u].l);
    dfs_front(tr[u].r);
}
void dfs_back(int u){
    if(!u)return ;
    dfs_back(tr[u].l);
    dfs_back(tr[u].r);
    db.push_back(u);
}
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        tr[i]={a,b};
    }
    dfs_front(1);
    dfs_back(1);
    d[0]=1;
    for(int i=1;i<=n;i++)d[i]=d[i-1]*2%mod;
    for(int i=0;i<da.size();i++)s1[da[i]]=i+1;
    for(int i=0;i<db.size();i++)s2[db[i]]=i+1;
    ll res=0;
    for(int i=1;i<=n;i++){
        if(s1[i]<s2[i]){
            ll c=(d[n-s1[i]]-d[n-s2[i]])%mod+mod;
            res=(res+c)%mod;
        }
    }
    printf("%lld\n",res);
    return 0;
}

B(* *) violence

Enumerate all palindrome strings, judge whether this number is a prime number, and store it in the array
What are the palindrome prime numbers smaller than this number obtained by dichotomy after sorting
Get (R) - get (L-1)

#include<algorithm>
#include<cstring>
#include<iostream>
#include<vector>
using namespace std;
typedef long long ll;
vector<ll>vec{2,3,5,7};
int find(ll x){
    return lower_bound(vec.begin(),vec.end(),x)-vec.begin();
}
bool check(ll x){
    if(x<=1)return false;
    for(ll i=2;i<=x/i;i++){
        if(x%i==0)return false;
    }
    return true;
}
ll change(ll x){
    ll res=0;
    while(x){
        res=res*10+x%10;
        x/=10;
    }
    return res;
}
int get(ll x){
    int c=find(x);
    if(vec[c]==x)c++;
    return c;
}
int main(){
    ll l,r;
    ll f=10;
    //cout<<change(1411)<<endl;
    for(int i=1;i<1e4;i++){
        ll a=i,b= change(i);
        if(i==10||i==100||i==1000||i==10000)f*=10;
        if(check(a*f+b))vec.push_back(a*f+b);
        for(int j=0;j<10;j++){
            if(check((a*10+j)*f+b))vec.push_back((a*10+j)*f+b);
            //cout<<(a*10+j)*f+b<<endl;
        }
    }
    sort(vec.begin(),vec.end());
    scanf("%lld%lld",&l,&r);
    printf("%d\n",get(r)-get(l-1));
    return 0;
}

I(* *) shortest circuit problem

For shops, schools and homes, the weight of the edge is the Manhattan distance of two points
One set of the shortest path template is enough

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 110,INF=0x3f3f3f3f;
int d[N][N];
int f[N];
bool st[N];
int n,m,S,F;
int x[N],y[N];
int dijkstra(){
    memset(f,0x3f,sizeof(f));
    memset(st,0,sizeof(st));
    f[0]=0;
    queue<int>que;que.push(0);
    while(1){
        int u=-1;
        for(int i=0;i<=S+1;i++){
            if(!st[i]&&(u==-1||f[u]>f[i]))u=i;
        }
        if(u==-1)return f[S+1];
        st[u]=true;
        for(int i=0;i<=S+1;i++){
            f[i]=min(f[i],f[u]+d[u][i]);
        }
    }
}
int main(){
    scanf("%d%d%d%d",&n,&m,&F,&S);
    for(int i=1;i<=S;i++){
        scanf("%d%d",&x[i],&y[i]);
    }
    x[0]=y[0]=1;
    x[S+1]=n,y[S+1]=m;
    for(int i=0;i<=S+1;i++){
        for(int j=0;j<=S+1;j++){
            int c=abs(x[i]-x[j])+abs(y[i]-y[j]);
            if(c<=F)d[i][j]=c;
            else d[i][j]=INF;
        }
    }
    printf("%d\n",dijkstra());
    return 0;
}

J(* * *) segment tree to find the maximum value of the interval

For a number x, it can be transferred from y (ABS {X-y} > = k)
Therefore, the array can be sorted and discretized to build a segment tree
x is transferred from the left and RIGHT sections respectively (c = max{LEFT, RIGHT})

  • C + 1 > original number, update
  • C + 1 < original number, not updated
    The final answer is the maximum value of the interval
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 3e5+5,INF=1e9;
int n,k;
int w[N];
vector<int>vec({-INF*2-5,INF*2+5});
struct aa{
    int l,r;
    int max;
}tr[N*4];
int find(int x){
    return lower_bound(vec.begin(), vec.end(),x)-vec.begin();
}
void pushup(int u){
    tr[u].max=max(tr[u<<1].max,tr[u<<1|1].max);
}
void build(int u,int l,int r){
    tr[u]={l,r,0};
    if(l==r){
        return ;
    }
    int mid=l+r>>1;
    build(u<<1,l,mid);
    build(u<<1|1,mid+1,r);
}
void modify(int u,int x,int v){
    if(tr[u].l==x&&tr[u].r==x){
        tr[u].max=max(tr[u].max,v);
        return ;
    }
    int mid=tr[u].l+tr[u].r>>1;
    if(x<=mid)modify(u<<1,x,v);
    else modify(u<<1|1,x,v);
    pushup(u);
}
int query(int u,int l,int r){
    if(tr[u].l>=l&&tr[u].r<=r){
        return tr[u].max;
    }
    int mid=tr[u].l+tr[u].r>>1;
    int c=0;
    if(l<=mid)c= query(u<<1,l,r);
    if(r>mid)c=max(c, query(u<<1|1,l,r));
    return c;
}
int main(){
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
//        int a;
        scanf("%d",&w[i]);
        vec.push_back(w[i]);
    }
    sort(vec.begin(),vec.end());
    vec.erase(unique(vec.begin(),vec.end()),vec.end());
    build(1,0,vec.size()-1);
    for(int i=1;i<=n;i++){
        int L=find(w[i]-k+1)-1,R=find(w[i]+k);
        int c=max(query(1,0,L), query(1,R,vec.size()-1));
        modify(1,find(w[i]),c+1);
    }
    printf("%d\n", query(1,0,vec.size()-1));
    return 0;
}

G(* *) two points + spfa / greedy (not written)

When an edge is updated, the degrees of the two endpoints also change
Therefore, spfa can be used to realize the effect of updating and then updating through deformation

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 550;
bool dist[N][N];
bool d[N][N];
bool st[N];
int f[N],g[N];
int n,m;
bool spfa(int x){
    memcpy(d,dist,sizeof(dist));
    memcpy(f,g,sizeof(f));
    memset(st,0,sizeof(st));
    queue<int>que;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(!d[i][j]&&f[i]+f[j]>=x){
                d[i][j]=d[j][i]=true;
                f[i]++;f[j]++;
                if(!st[i])que.push(i),st[i]= true;
                if(!st[j])que.push(j),st[j]= true;
            }
        }
    }
    while(que.size()){
        int i=que.front();que.pop();
        st[i]= false;
        for(int j=1;j<=n;j++){
            if(!d[i][j]&&f[i]+f[j]>=x){
                d[i][j]=d[j][i]=true;
                f[i]++;f[j]++;
                if(!st[i])que.push(i),st[i]= true;
                if(!st[j])que.push(j),st[j]= true;
            }
        }
    }
    for(int i=1;i<=n;i++){
        if(f[i]!=n-1)return false;
    }
    return true;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)dist[i][i]= true;
    for(int i=1;i<=m;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        g[a]++;g[b]++;
        dist[a][b]=dist[b][a]=true;
    }
    int l=1,r=2*n;
    while(l<r){
        int mid=l+r+1>>1;
        if(spfa(mid))l=mid;
        else r=mid-1;
    }
    printf("%d\n",l);
    return 0;
}

D(* *) backpack / search

If we can subtract the favorability, we can get the difference between the two final favorability (the final answer needs to ensure the minimum difference)
Then add the good moves together to get the sum of the two final good moves (used to judge whether it is greater than s)
Therefore, we can take the difference as the item size and the sum of favorability as the item value, and calculate the backpack size through n, Ai and Bi
Because the difference in favorability may be negative, adding a large number makes this interval all positive
You can get the answer through the backpack

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 12000+15,M = 6005;
int n,m;
int dp[33][N];
bool st[33][N];
int main(){
    scanf("%d%d",&n,&m);
    memset(dp,-0x3f,sizeof(dp));
    dp[0][M]=0;st[0][M]= true;
    for(int i=1;i<=n;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        int w=a-b,v=a+b;
        for(int j=0;j<N;j++){
            dp[i][j]=max(dp[i-1][j],dp[i][j]);
            if(!(i==1&&j==M))st[i][j]=st[i][j]||st[i-1][j];
            int c=j+w;
            if(c>=0&&c<N){
                dp[i][c]=max(dp[i][c],dp[i-1][j]+v);
                st[i][c]=st[i][c]||st[i-1][j];
            }
        }
//        for(int j=0;j<=10;j++){
//            printf("%d %d\n",dp[i][M+j],dp[i][M-j]);
//        }
//        puts("");
    }
    for(int i=0;i<=M;i++){
//        printf("%d %d\n",dp[n][M+i],dp[n][M-i]);
        if(dp[n][M+i]>m&&st[n][M+i]||dp[n][M-i]>m&&st[n][M-i]){
            printf("%d\n",i);
            return 0;
        }
    }
    printf("%d",-1);
    return 0;
}

E(* *) prefix and

A point corresponds to two straight lines. Corresponding to these two lines, we can write the straight line equation (similar practice occurs in the eight queens problem)

  • x + y + c = 0
    • x + y = c
  • x - y - c = 0
    • x - y = c

Therefore, we can compress two straight lines into one point and store them in two arrays (as long as we judge whether the straight line exists or not)
Because there is no intersection between lines with the same slope
So we need to consider the intersection of two straight lines
The total number is the number of points in array 1 + the number of points in array 2 - intersecting points
Enumerating the lines in the second array, we can get the two intersections of the line and the chessboard boundary

  • Through two intersections, we can map to two values in array 1, that is, an interval. We can check how many intersections there are in the interval (prefix and maintenance are enough)

Note that because the intersection may not be an integer point, we need to prefix and sum every two
for example
2 2
1 1
1 2
The answer should be 4

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1e6+5,M=1e6;
typedef long long ll;
int n,m;
ll res=0;
ll tr[N*2];
bool d1[2*N],d2[2*N];
int get_1(int x){
    int d=1+n,ans=n;
    return ans-abs(d-x);
}
int get_2(int x){
    int d=0,ans=n;
    return ans-abs(d-x);
}
int main(){
    scanf("%d%d",&n,&m);
    while(m--){
        int x,y;
        scanf("%d%d",&x,&y);
        d1[x+y]=true;d2[x-y+M]=true;
    }
    for(int i=2;i<=n+n;i++){
        tr[i]=tr[i-2];
        if(d1[i]){
            res+= get_1(i);
            tr[i]++;
        }
    }
    for(int i=1-n;i<=n-1;i++){
        if(!d2[i+M])continue;
        if(i<=0){
            int L=2-i,R=2*n+i;
            res+= get_2(i)-tr[R]+tr[L-2];
        }
        else{
            int L=i+2,R=2*n-i;
            res+= get_2(i)-tr[R]+tr[L-2];
        }
    }
    printf("%lld\n",res);
    return 0;
}

F(* * * * *) tree array + vector insert / balance tree

Don't explain in detail, just look at the code if you want to solve it

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<list>
using namespace std;
const int N = 5e5+5;
int tr[N],n,idx;
//Who are there in each paragraph
vector<int>lis[N];
//Number of each paragraph
vector<int>vec[N];
int lowbit(int x){
    return x&-x;
}
void add(int x){
    for(int i=x;i<N;i+= lowbit(i)){
        tr[i]++;
    }
}
int query(int x){
    int res=0;
    for(int i=x;i;i-= lowbit(i)){
        res+=tr[i];
    }
    return res;
}
int get_back(int x,vector<int>v,int sum){
    //How many people are there in front? There are sum-1 people in front
    int d= query(v[x]);
    return sum-1-d;
}
void pushback(int c,int i){
    ++idx;
    vec[c].push_back(idx);
    lis[idx].push_back(i);//Who are there in this paragraph
    add(idx);
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int c,a;
        scanf("%d%d",&c,&a);
        if(vec[c].empty()){
            //There's nowhere to jump the queue
            pushback(c,i);
        }
        else{
            int l=0,r=vec[c].size()-1;
            while(l<r){
                int mid=l+r>>1;
                if(get_back(mid,vec[c],i)<=a)r=mid;
                else l=mid+1;
            }
            int people= get_back(l,vec[c],i);
            if(people<=a){
                //There's a place to jump the queue
                int p_id=vec[c][l];
                int d=max((int)lis[p_id].size()-(a-people),0);
                add(p_id);lis[p_id].insert(lis[p_id].begin()+d,i);
            }
            else{
                //There's nowhere to jump the queue
                pushback(c,i);
            }
        }
    }
    bool flag= false;
    for(int i=1;i<=idx;i++){
        for(auto c:lis[i]){
            if(flag)printf(" ");
            printf("%d",c);
            flag=true;
        }
    }
    return 0;
}