CSP-J2020 semi-finals solution

Keywords: Algorithm CSP

CSP-J rematch tutorial: , don't miss the semi-finals.

T1: excellent power

Title Description

Generally speaking, a positive integer can be divided into the sum of several positive integers. For example, 1 = 1, 10 = 1 + 2 + 3 + 4, etc.
For a specific split of positive integer n, we call it "excellent" if and only if under this split, n is decomposed into several different positive integer powers of 2. Note that a number x can be expressed as a positive integer power of 2 if and only if x can be obtained by multiplying the positive integers 2 together.
For example, 10 = 8 + 2 = 23 + 21 is an excellent split. However, 7 = 4 + 2 + 1 = 22 + 21 + 20 is not an excellent split because 1 is not a positive integer power of 2.
Now, given a positive integer n, you need to determine whether there is an excellent split in all splits of this number. If yes, please give a specific splitting scheme.

input

The input file has only one line, a positive integer n, representing the number to be judged.

output

If there are good splits in all splits of this number. Then, you need to output each number in the split from large to small, separated by a space between the two adjacent numbers. It can be proved that after the order of splitting numbers is specified, the splitting scheme is unique.
If there is no good split, output "- 1" (without double quotation marks).

Reference solution

#include <bits/stdc++.h>
using namespace std;

/*
Definition: decompose into several different positive integer powers of 2
 Nature: even number, odd number, no excellent splitting

Idea:
If n is an even number, n is converted to base
10 -> 1010
*/
int a[110],n,k = 0;//k represents the subscript of the a array

int main(){
    cin>>n;
    //Special judgment of odd numbers
    if(n % 2 != 0){
        cout<<-1;
        return 0;
    }

    //Binary conversion
    int t = 1;//Represents the power of 2
    while(n != 0){
        if(n % 2 != 0){
            k++;
            a[k] = t;
        }
        t = t * 2;
        n = n / 2;
    }

    //Output results in reverse order
    for(int i = k;i >= 1;i--){
        cout<<a[i]<<" ";
    }
    return 0;
}

T2: live Award

Title Description

NOI2130 will be held soon. In order to increase the viewing, CCF decided to evaluate the results of each contestant one by one and broadcast the real-time award score line. The winning rate of this competition is w%, that is, the lowest score of the top w% players is the real-time score line.
More specifically, if the results of p contestants have been evaluated, the current planned number of winners is max(1, ⌊ p) × w% ⌋), where w is the percentage of awards, ⌊ x ⌋ means rounding down x,
max(x, y) represents the larger number of X and y. If any contestant has the same score, all contestants with parallel scores can win the prize, so the actual number of winners may be more than planned.
As a technician of the evaluation team, please help CCF write a live program.

input

Line 1 two positive integers n, w. Represent the total number of players and the award rate respectively.
There are n non negative integers in line 2, which represent the results of the players evaluated one by one.

output

There is only one line, including n non negative integers, which represent the contestants' scores one by one, and the real-time winning score line will be obtained. Two adjacent integers are separated by a space.

Reference solution

#include <bits/stdc++.h>
using namespace std;

/*
1.The number of winners is k = max (1), int (P ×  w%))
2.The scores of the contestants are non negative integers no more than 600
 Idea: use the array to count the number of people scoring each score
 Count k individuals from large to small, and the score corresponding to the last cycle is the required award score
*/
int a[610];
int n,w,x;

int main(){
    scanf("%d%d",&n,&w);
    int k;//Number of winners
    int ans;//Number of Statistics
    //Read in the scores of n people and count one by one
    for(int i = 1;i <= n;i++){
        scanf("%d",&x);
        a[x]++;//Count the number of people corresponding to each score
        //Calculate the number of winners
        k = max(1,int(i * w / 100.0));
        ans = 0;
        //Count down > = k individuals from the number of people with the highest score
        for(int j = 600;j >= 0;j--){
            if(ans + a[j] < k) ans += a[j];//+=
            else{
                printf("%d ",j);
                break;
            }
        }
    }
	return 0;
}

T3: expression (expr)

Title Description

Little C is keen on learning mathematical logic. One day, he found a special logical expression. In this logical expression, all operands are variables, and their values can only be 0 or 1. The operation is carried out from left to right. If there are parentheses in the expression, the value of the subexpression in parentheses is evaluated first. In particular, this expression has and only has the following operations:

1. And operation: A & b. If and only if the values of a and b are 1, the value of the expression is 1. In other cases, the value of the expression is 0.

2. Or operation: a | b. If and only if the values of a and b are 0, the value of the expression is 0. In other cases, the value of the expression is 1.

3. Inverse operation:! a. If and only if the value of a is 0, the value of the expression is 1. In other cases, the value of the expression is 0.

Little C wants to know what the value of the original expression is when a logical expression and the initial value of each operand are given, and then the value of an operand is reversed.

To simplify the processing of expressions, we have the following conventions:

The expression is entered as a suffix expression. The suffix expression is defined as follows:

1. If e is an operand, the suffix expression of E is itself.

2. If e is an expression in the form of E1 op E2, where op is any binary operator and the priority is not higher than the operators outside the brackets in E1 and E2, the suffix of E is E1 'E2' op, where E1 'and E2' are the suffixes of E1 and E2 respectively.

3. If e is an expression in the form of (E1), the suffix of E1 is the suffix of E.
Meanwhile, for convenience, input:

a) There is a space on the left and right of and operator (&), or operator (|) and negation operator (!), but there is no space at the end of the expression.
b) Operands are spliced by the lowercase letter x and a positive integer, which represents the subscript of the variable. For example, x10 represents the variable x10 with subscript 10. The data guarantees that each variable occurs exactly once in the expression.

input

The first line contains a string s representing the expression described above.
The second line contains a positive integer n, which represents the number of variables in the expression. The subscripts of variables in the expression are 1,2,..., n.

The third line contains n integers, and the i integer represents the initial value of the variable xi.

The fourth line contains a positive integer q, indicating the number of queries.

Next q lines, each line a positive integer, indicating the subscript of the variable to be inverted. Note that the modification of each query is temporary, that is, the modification in the previous query will not affect the subsequent query.

The data ensures that the input expression is legal. The initial value of the variable is 0 or 1.

output

Output a total of q lines, each line with a 0 or 1, indicating the value of the expression under the query.

#include <bits/stdc++.h>
using namespace std;

/*
When the value of an operand is reversed, what is the value of the original expression
 Idea:
1.Read in the expression and build the expression into a binary tree
2.Calculate the value of the expression
3.Search deeply to find out which node values have an impact on the results after modification
*/
const int N = 1e6 + 10;
struct node{
    int to,next;
}a[N];//Adjacency table
int pre[N],k;//Stores the number of the last edge starting from each point
int num[N];//Store the value of each node of the binary tree
char c[N];//Storage operator
int m;//Subscript representing c array
bool f[N];//Mark which points have changed values that affect the results
int n;
string s,w;//w is used to store the subscript of each operand
stack<int> st;//Expression used to evaluate suffixes

//Jianbian
void add(int u,int v){
    k++;
    a[k].to = v;
    a[k].next = pre[u];
    pre[u] = k;
}

//Search deeply for which node values will affect the results after modification
void dfs(int x){
    f[x] = true;
    if(x <= n) return;//If it is a leaf node
    if(c[x] == '!') dfs(a[pre[x]].to);
    else{
        int n1 = a[pre[x]].to,n2 = a[a[pre[x]].next].to;
        if(c[x] == '&'){
            if(num[n1] == 1) dfs(n2);
            if(num[n2] == 1) dfs(n1);
        }else if(c[x] == '|'){
            if(num[n1] == 0) dfs(n2);
            if(num[n2] == 0) dfs(n1);
        }
    }
}

int main()
{
    getline(cin,s);
    cin>>n;
    for(int i = 1;i <= n;i++){
        scanf("%d",&num[i]);
    }

    //Analyzing expressions, building trees
    int x,y;
    m = n;
    for(int i = 0;i < s.size();i++){
        if(isdigit(s[i])){
            w = w + s[i];
            //If consecutive numbers end
            if(i==s.size()-1||!isdigit(s[i+1])){
                st.push(atoi(w.c_str()));//Subscript the operand onto the stack
                w = "";
            }
        }else if(s[i] == '!'){
            //If it's an inverse operator
            m++;
            c[m] = s[i];//The number of the operator is m
            x = st.top();//Take the top element of the stack to operate
            st.pop(); //Out of stack
            //Jianbian
            add(m,x);
            num[m] = !num[x];
            st.push(m);
        }else if(s[i] == '&' || s[i] == '|'){
            //If it is the & | operator
            m++;
            c[m] = s[i];
            //Take 2 operands
            x = st.top();
            st.pop();
            y = st.top();
            st.pop();
            //Jianbian
            add(m,x);
            add(m,y);
            //Calculate the value of the node
            if(s[i] == '&') num[m] = num[x] & num[y];
            else if(s[i] == '|') num[m] = num[x] | num[y];

            st.push(m);
        }
    }

    int ans = num[st.top()];
    //cout<<ans;
    //Search deeply for which node values will affect the results after modification
    dfs(st.top());//Search deeply from the root

    //q queries
    int q;
    cin>>q;
    while(q--){
        scanf("%d",&x);
        if(f[x]==true) printf("%d\n",!ans);
        else printf("%d\n",ans);
    }

    return 0;
}

T4: grid access (number)

Title Description

Set n × m, there is an integer in each square. There is a little bear. If he wants to go from the upper left corner to the lower right corner of the figure, he can only go up, down or right one grid at a time, and he can't repeat the square he has gone through or go out of the border. The little bear will take all the integers in the square and find the maximum sum of integers it can get.

input

Line 1 two positive integers n, m.
Next, there are m integers in n rows, representing the integers in each square in turn.

output

An integer that represents the maximum value of the sum of integers that the bear can get.

Reference procedure

#include <bits/stdc++.h>
using namespace std;
/*
Go from the upper left corner to the lower right corner
 Each step can only go up, down or right one space
 You cannot repeat a square that has been passed

The result of calculation shall be long long
*/
const int N = 1010;
int a[N][N];//The value of each point read in
typedef long long LL;
LL f[N][N];
int n,m;

int main(){
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i++){
        for(int j = 1;j <= m;j++){
            scanf("%d",&a[i][j]);
        }
    }

    /*
    DP Find the maximum value of the sum of numbers passing through each point
    For each column, it is required to go from top to bottom to the maximum value of the sum of numbers passed by each point
    It is also required to go from bottom to top to the maximum value of the sum of numbers passed by each point
    */
    memset(f,-0x7f,sizeof(f));

    LL ma;//Go to the number and maximum of each grid
    f[1][0] = 0;
    for(int j = 1;j <= m;j++){
        //From top to bottom
        ma = -1e18;
        for(int i = 1;i <= n;i++){
            ma = max(ma,f[i][j-1]) + a[i][j];
            f[i][j] = max(f[i][j],ma);
        }

        //From bottom to top
        ma = -1e18;
        for(int i = n;i >= 1;i--){
            ma = max(ma,f[i][j-1]) + a[i][j];
            f[i][j] = max(f[i][j],ma);
        }
    }

cout<<f[n][m];
return 0;
}

Posted by archangel_617b on Wed, 22 Sep 2021 05:34:10 -0700