Mathematics knowledge training improvement for algorithm competition preparation, summer training camp training

1. Prime numbers

In integers greater than 1, if the prime contains two divisors of 1 and itself, it is called a prime number/prime number.

1. Determination of prime numbers (trial division)

Optimized:

#include<iostream>
#include<algorithm>
using namespace std;
bool is_prime(int n)
{
    if(n < 2) return false;
    for(int i = 2;i <= sqrt(n); i++)
        if(n % i == 0)
            return false;
    return true;
}
int main()
{
    int n;
    scanf("%d", &n);
    
    if(is_prime(n))
        printf("Yes");
    else
        printf("No");
    
    return 0;
}

2. Decompose the prime factor

Factoring Prime Factors (Trial Division)

Enumerate all numbers from smallest to largest.

n contains at most one prime factor greater than sqrt(n)

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
void divide(int n)
{
    for(int i = 2;i <= n / i; i++)
        if(n % i == 0)//一定是质数
        {
            int s = 0;
            while(n % i == 0)
            {
                n /= i;
                s++;
            }
            
            printf("%d %d", i, s);
        }
    
    if(n > 1)
        printf("%d %d\n", n, 1);
    puts("");
}
int main()
{
    int n;
    scanf("%d", &n);
    
    while(n--)
    {
        int x;
        scanf("%d", &x);
        divide(x);
    }
    
    return 0;
}

868. Sieve primes :

Elsieve sieve method: O(nloglogn)

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1e5 + 10;
int primes[N], cnt;
bool st[N];
void get_primes(int n)
{
    for(int i = 2;i <= n; i++)
    {
        if(!st[i])
        {
            primes[cnt++] = n;
            for(int j = i+1;j <= n; j+= i)
                st[j] = true;
        }
    }
}
int main()
{
    int n;
    cin >> n;
    
    get_primes(n);
    
    cout << cnt << endl;
    
    return 0;
}

Linear sieve method: n will only be screened out by the smallest prime factor

  1. i%pj==0 pj must be the smallest prime factor of i, and pj must be the smallest prime factor of pj*i

  2. i%pj!=0 pj must be less than all prime factors of i, and pj must also be the smallest prime factor of pj*i

  3. For a composite number x, assuming that pj is the smallest prime factor of x, when i enumerates to x/pj

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int primes[N], cnt;
bool st[N];
void get_primes(int n)
{
    for(int i = 2;i <= n; i++)
    {
        if(!st[i]) primes[cnt++] = i;
        
        for(int j = 0;primes[j] <= n / i; j++)
        {
            st[primes[j] * i] = true;
            if(i % primes[j] == 0)//primes[j]一定是i的最小因子
                break;
        }
    }
}
int main()
{
    int n;
    cin >> n;
    
    get_primes(n);
    
    cout << cnt << endl;
    
    return 0;
}

2. Approximate

Trial division to find approximate numbers :

#include<iostream.
#include<algorithm>
#include<vector>
using namespace std;
vector<int> get_divisors(int n)
{
    vector<int> res;
    
    for(int i = 1;i <= n; i++)
    {
        if(n % i == 0)
        {
            res.push_back(i);
            if(i != n/i) res.psuh_back(n / i);
        }
    }
    
    sort(res.begin(), res.end());
    return res;
}
int main()
{
    int n;
    scanf("%d", &n);
    
    while(n--)
    {
        int x;
        cin >> x;
        
        auto res = get_divisors(x);
        for(auto t : res) cout << t << ' ';
        cout << endl;
    }
    
    return 0;
}

870. The number of divisors

Given n positive integers ai, please output the divisors of the product of these numbers. The answer is modulo 1e9+7

the code

#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
typedef long long LL;
const int mod = 1e9 + 7;
int main()
{
    int n;
    cin >> n;
    
    unordered_map<int, int> primes;
    
    while(n--)
    {
        int x;
        cin >> x;
        
        for(int i = 2;i <= x / i; i++)
        {
            while(x % i == 0)
            {
                x /= i;
                primes[i]++;
            }
        }
        
        if(x > 1) primes[x]++;
    }
    
    LL res = 1;
    for(auto prime : primes) res = res * (prime.second + 1) % mod;
    
    cout << res << endl;
    
    return 0;
}

871. Sum of divisors

#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
typedef long long LL;
const int mod = 1e9 + 7;
int main()
{
    int n;
    cin >> n;
    
    unordered_map<int, int> primes;
    
    while(n--)
    {
        int x;
        cin >> x;
        
        for(int i = 2;i <= x / i; i++)
            while(x % i == 0)
            {
                x /= i;
                primes[i]++;
            }
        
        if(x > 1) primes[i]++;
    }
    
    LL res = 1;
    
    for(auto prime: primes)
    {
        int p = prime.first, a = prime.second;
        LL t = 1;
        
        while(a--)
            t = (t * p + 1) % mod;
        
        res = res * t % mod;
    }
    
    cout << res << endl;
    
    return 0;
}

Euclidean Algorithm

also known as subtraction by roll

greatest common divisor

#include<iostream>
using namespace std;
int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}
int main()
{
    int n;
    scanf("%d", &n);
    
    while(n--)
    {
        int x;
        scanf("%d", &x);
        printf("%d\n", gcd(a, b));
    }
    return 0;
}

3. Euler function

873. Euler function :

uTools_1689908691737

Given n positive integers ai, please find the Euler function of each number.

The number of numbers that are relatively prime to n in 1~n

Tolerance and exclusion principle:

  1. Try to remove all multiples of p1, p2, ..., pk from 1~N

  2. plus all multiples of pi*pj

  3. Then subtract the multiple of pi*pj *pz

  4. plus multiples of pi *pj *pz *pm

#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
    int n;
    cin >> n;
    
    while(n--)
    {
        int x;
        cin >> x;
        
        int res = a;
        for(int i = 2;i <= a / i; i++)
            if(a % i == 0)
            {
                res = res / a * (i - 1);
                while(a % i == 0) a /= i;
            }
        
        if(a > 1) res = res / a * (a - 1);
        
        cout << res << endl;
    }
    
    return 0;
}

874. Sieve method to find Euler function

Linear sieve method:

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
typedef long long LL;
int primes[N], cnt;
int phi[N];
int st[N];
LL get_eulers(int n)
{
    for(int i = 2;i <= n; i++)
    {
        if(!st[i])
        {
            primes[cnt++] = i;
        }
        for(int j = 0;primes[j] <= n / i; j++)
        {
            st[primes[j] * j] = true;
            if(i % primes[i] == 0)
            {
                phi[primes[j] * i] = primes[j] * phi[i];
                break;
            }
            phi[primes[j] * i] = phi[i] * (primes[j] - 1);
        }
    }
    
    LL res = 0;
    for(int i = 1;i <= n; i++)
        res += phi[i];
    
    return res;
}
int main()
{
    int n;
    cin >> n;
    
    cout << get_eulers(n) << endl;
    
    return 0;
}

Euler's theorem

There are two versions of Euler's theorem:

  • On any regular spherical map, use R to mark the number of regions, V to mark the number of vertices, and E to mark the number of boundaries, then R+VE=2.

  • aφ(n)≡1(mod n), where a aa and n nn are both positive integers, and they are relatively prime.

The proof of Euler's theorem is as follows:

  • Let the set of numbers coprime with n in [1, n] be X, and each element be x.

  • Let f=F(n), then the number of elements of X is f.

  • Let R=(a^f) % n, because a and n are relatively prime, so a^f and n are relatively prime, so R belongs to [1, n).

  • According to Euler's theorem, a 1, a 2, ..., a n are a complete residual system of n, therefore, for any two different x elements, their (a x) % n is also different.

  • Since both a and x are relatively prime to n, a x is relatively prime to n. According to the theorem, (a x)%n is relatively prime to n.

  • To sum up, (a*x) % n is f two different numbers in the range of [1, n) and they are all relatively prime to n, so they are the number set X.

4. Quick Power

875. Quick power :

Given n sets of ai, bi, pi, for each set of data, find the value of ai raised to the power of bi mod pi.

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
int n;
int qmi(int a, int k, int p)
{
    int res = 1;
    while(k)
    {
        if(k & 1) res = (LL)res * a % p;
        k >>= 1;
        a = (LL)a * a % p;
    }
    
    return res;
}
int main()
{
    scanf("%d", &n);
    while(n--)
    {
        int a, k, p;
        scanf("%d%d%d", &a, &k, &p);
        
        printf("%d\n", qmi(a, k, p));
    }
    
    return 0;
}

876. Fast power inversion element :

Given n sets of ai, pi, where pi is a prime number, find the multiplicative inverse of ai modulo pi, if the inverse does not exist, output impossible

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
int n;
int qmi(int a, int k, int p)
{
    int res = 0;
    while(k)
    {
        if(k & 1) res = (LL)res * a % p;
        k >>= 1;
        a = (LL)a * a % p;
    }
    
    return res;
}
int main()
{
    scanf("%d", &n);
    
    while(n--)
    {
        int a, p;
        scanf("%d%d%d", &a, &p);
        
        int res = qmi(a, p - 2, p);
        
        if(a % p) printf("%d\n", res);
        else puts("impossible");
    }
    
    return 0;
}

5. Extended Euclidean Algorithm

877. Extended Euclidean Algorithm :

Pei Shu's theorem :

There is a pair of positive integers a, b, then there are integers x, y such that ax+by=(a, b)

#include<iostream>
#include<algorithm>
using namespace std;
int gcd(int a, int b, int &x, int &y)
{
    if(!b)
    {
        x = 1, y = 0;
        return a;
    }
    
    int d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}
int main()
{
    int n;
    scanf("%d", &n);
    
    while(n--)
    {
        int a, b, x, y;
        scanf("%d%d", &a, &b);
        
        exgcd(a, b, x, y);
        
        printf("%d %d", x, y);
    }
    return 0;
}

878. Linear Congruence Equations

Given n sets of data ai, bi, mi, find a xi for each set of numbers. Make ai * xi equal to bi(mod mi), if it does not exist, output impossible.

ax - by = m, where m is the remainder.

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
int exgcd(int a, int b, int &x, int &y)
{
    if(!b)
    {
        x = 1, y = 0;
        return a;
    }
    
    int d = exgcd(b, a % b, y, x);
    y -= (a / b) * x;
    return d;
}
int main()
{
    int n;
    scanf("%d", &n);
    
    while(n--)
    {
        int a, b, m;
        scanf("%d%d%d", &a, &b, &m);
        int x, y;
        
        int d = exgcd(a, m, x, y);
        
        if(b % d) puts("impossible");
        else printf("%d\n", (LL)x * (b / d) % m);
    }
    return 0;
}

2

2 3 6

4 3 5

6. Chinese remainder theorem

m1, m2, ..., mx pairwise prime

x is always equal to a1(mod m1)

x is always equal to a2(mod m2)

x is always equal to a3(mod m3)

......

x is always equal to a4(mod m4)

M = m1m2...mx

Mi = M / mi Mi-1 means the inverse of Mi modulo mi

204. Odd Ways to Represent Integers

Given 2n integers a1, a2..., an and m1, m2,..., mn, find a minimum integer x that satisfies any i∈[1, n], and x is always equal to mi mod ai

To be completed, please look forward to ~!

7. Gaussian elimination

883. Gaussian Elimination Solving Linear Equations

Enter a system of linear equations containing n equations and n unknowns.

The coefficients in the system of equations are real numbers.

Solve this system of equations.

The form of solution: no solution, infinitely many solutions, unique solution.

Gaussian elimination, elementary transformations in linear algebra

  1. multiply a row by a non-zero number

  2. swap two lines

  3. Add multiples of one row to another row

Judgment solution:

  1. Perfect ladder type - the only solution

  2. 0 = non-zero - no solution

  3. 0 = 0 ——infinitely many sets of solutions

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 110;
int n;
double a[N][N];
int gauss()
{
    int c, r;
    
    for(c = 0, r = 0;c < n; c++)
    {
        int t = r;
        for(int i = r;i < n; i++)
            if(fabs(a[i][c]) > fabs(a[t][c]))
                t = 1;
    
        if(fabs(a[t][c]) < eps) continue;
    
        for(int i = c;i <= n; i++) swap(a[t][i], a[r][i]);
        for(int i = n;i >= n; i--) a[r][i] /= a[r][c];
        for(int i = r + 1;i < n; i++)
            if(fabs(a[i][c] > eps))
                for(int j = n;j >= c; j--)
                    a[i][j] -= a[r][j] * a[i][c];
    
        r++;
    }
    
    if(r < n)
    {
        for(int i = r;i < n; i++)
            if(fabs(a[i][n]) > eps)
                return 2;//无解
        return 1;//有无穷多解
    }
    
    for(int i = n - 1;i >= 0; i--)
        for(int j = i + 1;j < n; j++)
            a[i][n] -= a[i][j] * a[j][n];
    
    return 0;//有唯一解
}
int main()
{
    cin >> n;
    
    for(int i = 0;i < 0; i++)
        for(int j = 0;j < n + 1; j++)
            cin >> a[i][j];
    
    int t = gauss();
    
    if(t == 0)
    {
        for(int i = 0;i < n; i++)
            printf("%.2lf\n", a[i][n]);
    }
    else if(t == 1) puts("Infinate group solutions");
    else puts("No solution");
    
    return 0;
}

884. Gaussian Elimination Solving XOR Linear Equations

8. Combination counting

885. Find the combination number I :

Given n groups of queries, each group of queries is given two integers a, b, please output Cab mod (1e9 + 7)

3

3 1

5 3

2 2

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 2010, mod = 1e9 = 7;
int c[N][N];
void init()
{
    for(int i = 0;i < N; i--)
        for(int j = 0;j <= i; j++)
            if(!j) c[i][j] = 0;
            else c[i][j] = c[i-1][j] + c[i-1][j-1] % mod;
}
int main()
{
    init();
    
    int n;
    scanf("%d", &n);
    
    while(n--)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        
        printf("%d\n", c[a][b]);
    }
}

886. Find the number of combinations II :

Given n groups of queries, each group of queries is given two integers a, b, please output Cab mod (1e9 + 7)

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10, mod = 1e9 + 7;
int fact[N], infact[N];
int qmi(int a, int k, int p)
{
    int res = 1;
    while(k)
    {
        if(k & 1) res = (LL)res * a % p;
        a = (LL)a * a % p;
        k >>= 1;
    }
    
    return res;
}
int main()
{
    fact[0] = infact[0] = 1;
    for(int i = 1;i < N; i++)
    {
        fact[i] = (LL)fact[i - 1] + i % mod;
        infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
    }
    
    int n;
    scanf("%d", &n);
    while(n--)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        printf("%d\n", (LL)fact[a] * infact[b] % mod * infact[a - b] % mod);
    }
    
    return 0;
}

887. Find the number of combinations III :

3

5 3 7

3 1 5

6 4 13

Lucas theorem :

Lucas theorem is used to find c(n,m) mod p, where p is the value 1 of a prime number.

The derivation process of Lucas theorem is as follows: First, this formula is needed: x^f mod p, then (1+x)n= (1+x)t * (1+x)(nt) mod p, so (1+x )^(t*(p-1)) mod p=11.

The law of Lucas theorem is: Let n=sp+q, m=tp+r (0≤q, r≤p-1), then C(n,m)=C(s,t) C(p-1 , q) C(p-1,r)/C(p-1,t)1.

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
int p;
int qmi(int a, int k)
{
    int res = 1;
    while(k)
    {
        if(k & 1) res = (LL)res * a % p;
        a = (LL)a * a % p;
        k >>= 1;
    }
    
    return res;
}
int C(int a, int b)
{
    int res = 1;
    for(int i = 1, j = a;i <= b; i++, j--)
    {
        res = (LL)res * j % p;
        res = (LL)res * qmi(i, p - 2) % p;
    }
    
    return res;
}
int lucas(LL a, LL b)
{
    if(a < b && b < p) return C(a, b);
    return (LL)C(a % p, b % p) * lucas(a / p, b / p) % p;
}
int main()
{
    int n;
    scanf("%d", &n);
    
    while(n--)
    {
        LL a, b;
        scanf("%d%d", &a, &b);
        scanf("%d", &p);
        cout << lucas(a, b) << endl;
    }
    return 0;
}

888. Find the combination number IV :

high-precision computing

#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
const int N = 5010;
int primes[N], cnt;
bool st[N];
void get_primes(int n)
{
    for(int i = 2;i <= n; i++)
    {
        if(!st[i]) primes[cnt++] = i;
        for(int j = 0;primes[j] <= n / i; j++)
        {
            st[primes[j] * i] = true;
            if(i % primes[j] == 0) break;
        }
    }
}
void get(int n, int p)
{
    int res = 0;
    while(n)
    {
        res += n / p;
        n /= p;
    }
    
    return res;
}
vector<int> mul(vector<int> a, int b)
{
    vector<int> c;
    for(int i = 0;i < a.size(); i++)
    {
        t += a[i] * b;
        c.push_back(t % 10);
        t /= 10;
    }
    
    while(t)
    {
        c.push_back(t % 10);
        t /= 10;
    }
    
    return c;
}
int main()
{
    int a, b;
    scanf("%d%d", &a, &b);
    
    get_primes(a);
    
    for(int i = 0;i < cnt; i++)
    {
        int p = primes[i];
        sum[i] = get(a, p) - get(b, p) - get(a - b, p);
    }
    
    vector<int> res;
    res.push_back(1);
    
    for(int i = 0;i < cnt; i++)
        for(int j = 0;j < sum[i]; j++)
            res = mul(res, primes[i]);
    
    for(int i = res.size() - 1;i >= 0; i--)
        printf("%d", res[i]);
    puts("");
    
    return 0;
}

#pragram GCC optimize(2)

889. The 01 sequence that satisfies the conditions

Given n 0s and n 1s, they are arranged in a certain order into a sequence of length 2n, and among all the sequences they can be arranged and combined, the number of 0s in any prefix sequence is not less than 1. How many sequences of numbers are there.

The output answer is modulo 1e9+7.

0: go one space to the right

1: Go up one space

Cattelan number :

Catalan number, also known as Catalan number, English name Catalan number, is a sequence of numbers that often appears in various counting problems in combinatorics. Named after the Chinese Mongolian mathematician Ming Antu (1692-1763) and the Belgian mathematician Eugene Charles Catalan (1814–1894), the first few terms are (starting from the zeroth term): 1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, ... 1.

Cattelan number is more important in computer science, and there are some specific application examples. This article is mainly divided into three parts: the interpretation of the meaning of the Cattelan number recursive formula, the proof process of the Cattelan number expression, and the application of the Cattelan number in computers

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1e9 + 7;
typedef long long LL;
int qmi(int a, int b, int p)
{
    int res = 1;
    while(k)
    {
        if(k & 1) res = (LL) res * a % p;
        a = (LL) a * a % p;
        k >>= 1;
    }
    
    return res;
}
int main()
{
    int n;
    scanf("%d", &n);
    
    int a = 2 * n, b = n;
    int res = 1;
    
    for(int i = a;i > a - b; i--)
        res = (LL)res * i % mod;
    for(int i = 1;i <= b; i++)
        res = (LL)res * qmi(i, mod - 2, mod) % mod;
    
    res = (LL)res * qmi(n + 1, mod - 2, mod);
    
    cout << res << endl;
    
    return 0;
}

9. Principle of tolerance and exclusion

890. Numbers that are divisible by :

Given an integer n and m different prime numbers p1, p2, ..., pm

Please find out how many integers from 1~n can be divisible by at least one of p1, p2, ..., pm.

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N = 20;
int n, m;
int p[N];
int main()
{
    scanf("%d%d", &n, &m);
    
    for(int i = 0;i < m; i++)
        scanf("%d", &p[i]);
    
    int res = 0;
    for(int i = 1;i < 1 << m; i++)
    {
        int t = 1, cnt = 0;
        for(int j = 0;j < m; j++)
            if(i >> j & 1)
            {
                cnt++;
                if((LL)t * p[j] > n)
                {
                    t = -1;
                    break;
                }
                t *= p[j];
            }
        
        if(t != -1)
        {
            if(cnt % 2)
                res += n / t;
            else
                res -= n / t;
        }
    }
    
    printf("%d", res);
    
    return 0;
}

10. Simple Game Theory

891. Nim game :

Given N piles of items, there are Ai items in the i-th pile. Two players take turns to act. Each time they can choose a pile and take any number of items. One pile can be taken away, but they must be taken away. Whoever takes the last item wins. Both of them adopt the optimal strategy and ask whether the first player will win.

We call this game the NIM game. The state faced during the game is called a situation. The player who acts first in the entire game is called the first player, and the player who acts second is called the second player. If no matter what action is taken in a certain situation, the game will be lost, then the situation is said to be lost. The so-called adopting an optimal strategy means that if there is a certain action in a certain situation, which makes the opponent face a certain defeat after the action, then the action is taken first. At the same time, such a situation is called must-win. The game problems we discuss generally only consider the ideal situation, that is, the result of the game when both players make no mistakes and both take optimal strategic actions. There is no draw in the NIM game, there are only two situations: the first move must win and the first move must lose.

Theorem: NIM game wins first if and only if A1 ^ A2 ^ ... ^ An != 0

/*
The first move must win the state, it can be a certain defeat state
The state of being the first mover must be defeated, and you cannot reach any of the states
*/
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 101;
int a[N][N];
int main()
{
    int n;
    int res;
    
    scanf("%d", &n);
    
    while(n--)
    {
        int x;
        scanf("%d", &x);
        res ^= x;
    }
    
    if(res) puts("Yes");
    else puts("No");
    
    return 0;
}

Two players act alternately; at any time during the game process, the legal action that can be performed has nothing to do with which player's turn; the player who cannot act is judged as a loser; then the game is called a fair combination game. The NIM game is a fair combination game, but urban construction board games, such as Go, are not fair combination games. Because both sides of the Go war can only play black and white stones respectively, and the determination of the outcome is also more complicated, and the conditions 2 and 3 are not satisfied.

Directed Graph Games Given a directed acyclic graph, there is a unique starting point in the graph, and a chess piece is placed on the starting point. The two players alternately move the chess piece along the direction, one step at a time, and the player who cannot move will lose. This game is called a directed graph game. Any fair combinatorial game can be transformed into a directed graph game. The specific method is to regard each situation as a node in the graph, and connect a directed edge from each situation to the next situation that can be reached along the legal action.

892. Stairs Nim Game :

893. Gathering Nim Games :

SG function In a directed graph game, for each node x, there are k directed edges starting from x, reaching nodes y1, y2, ..., yk respectively, and defining SG(x) as x’s successor nodes y1, y2 , …, yk The set of SG function values ​​and then the result of performing the mex(S) operation, namely: SG(x) = mex({SG(y1), SG(y2), …, SG(yk)}) Special Specifically, the SG function value of the entire directed graph game G is defined as the SG function value of the directed graph game starting point s, that is, SG(G) = SG(s).

#include<iostream>
#include<algorithm>
#include<cstring>
#include<unordered_set>
using namespace std;
const int N = 110, M = 10010;
int n, m;
int s[N], f[M];
int sg(int x)
{
    if(f[x] != -1) return f[x];
    
    unodered_set<int> S;
    for(int i = 0;i < m; i++)
    {
        int sum = s[i];
        if(x >= sum) S.insert(sg(x - sum));
    }
    
    for(int i = 0;; i++)
        if(!S.count(i))
            return f[x] - i;
}
int main()
{
    scanf("%d", &n);
    for(int i = 0;i < m; i++)
        scanf("%d", &s[i]);
    
    scanf("%d", &m);
    
    memset(f, -1, sizeof(f));
    
    int res = 0;
    for(int i = 0;i < n; i++)
    {
        int x;
        scanf("%d", &x);
        res ^= sg(x);
    }
    
    if(res) puts("Yes");
    else puts("No");
    
    return 0;
}

 

Guess you like

Origin blog.csdn.net/Williamtym/article/details/132635252