Basic algorithm Course August 24, 2021

Posted by iamchris on Sat, 25 Dec 2021 00:31:37 +0100

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 20000,M=2000000;
int h[N], e[M], ne[M], idx;
void add(int a, int b)  // Add an edge a - > b
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
int match[N],st[N];
bool find(int x)
{
    for (int i = h[x]; i != -1; i = ne[i])
    {
        int j = e[i];
        if (!st[j])
        {
            st[j] = true;
            if (match[j] == 0 || find(match[j]))
            {
                match[j] = x;
                return true;
            }
        }
    }
    
    return false;
}
int main(){
    int n1,n2,m;
    cin>>n1>>n2>>m;
    memset(h, -1, sizeof h);
    while(m--){
        int a,b;
        cin>>a>>b;
        add(a,b);
    }
    int ans=0;
    for(int i=1;i<=n1;i++){
        memset(st, 0, sizeof st);
        if(find(i))ans++;
    }
    cout<<ans;
    
}

#include<bits/stdc++.h>
using namespace std;
const int N = 200,M=20000;
int h[N], e[M], ne[M], idx;
int match[N],st[N];
int n,m;
void add(int a, int b)  // Add an edge a - > b
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
bool find(int x){
    for(int i=h[x];~i;i=ne[i]){
        int j=e[i];
        if(st[j])continue;
        st[j]=1;
        if(match[j]==0||find(match[j])){
            match[j]=x;
            return 1;
        }
    }
    return 0;
}
int main(){
    cin>>m>>n;
    memset(h, -1, sizeof h);
    while(1){
        int a,b;
        cin>>a>>b;
        if(a==-1)break;
        add(b,a);
    }
    int ans=0;
    for(int i=m+1;i<=n;i++){
        memset(st, 0, sizeof st);
        if(find(i))ans++;
    }
    printf("%d\n",ans);
    for(int i=1;i<=m;i++)if(match[i])printf("%d %d\n",i,match[i]);
}

01 Backpack

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int n,m;
int a,b;
int dp[1001];
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a>>b;
        for(int j=m;j>=a;j--)dp[j]=max(dp[j],dp[j-a]+b);
    }
    cout<<dp[m];
}

Complete Backpack

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int n,m;
int dp[1001];
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        int v,w;
        cin>>v>>w;
        for(int j=v;j<=m;j++)dp[j]=max(dp[j],dp[j-v]+w);
    }
    cout<<dp[m];
}

Multiple Backpack

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int n,m;
int v[1000],w[1000],s[1000];
int dp[1000][1000];
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>v[i]>>w[i]>>s[i];
    for(int i=1;i<=n;i++){
        for(int j=0;j<=m;j++){
            for(int k=0;k<=s[i]&&k*v[i]<=j;k++){
                dp[i][j]=max(dp[i][j] , dp[i-1][j-k*v[i]]+k*w[i]);
            }
        }
    }
    cout<<dp[n][m];
}

Binary optimization
(that is to transform the multiple knapsack problem into a 01 knapsack problem
(optimize the third layer without enumerating one by one

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 20001;
int v[N],w[N],n,m,dp[N],cnt;
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        int a,b,s;
        cin>>a>>b>>s;
        int k=1;
        while(k<=s){
            cnt++;
            v[cnt]=k*a;
            w[cnt]=k*b;
            s-=k;
            k*=2;
        }
        if(s>0){
            cnt++;
            v[cnt]=s*a;
            w[cnt]=s*b;
        }
    }
    //Converted to 01 knapsack problem (positive order traversal will make errors, and reverse order is required)
    for(int i=1;i<=cnt;i++){
        for(int j=m;j>=v[i];j--){
            dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
        }
    }
    cout<<dp[m];
}

Group Backpack

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 105;
int v[N][N],w[N][N],s[N],n,m,dp[N];
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>s[i];
        for(int j=1;j<=s[i];j++)
        cin>>v[i][j]>>w[i][j];
    }
    for(int i=1;i<=n;i++){
        for(int j=m;j>=0;j--){
            for(int k=1;k<=s[i];k++){
                if(j>=v[i][k])dp[j]=max(dp[j],dp[j-v[i][k]]+w[i][k]);
            }
        }
    }
    cout<<dp[m];
}

Longest ascending subsequence problem solving Report
Given a sequence with length N (w[N]), find the longest length of the subsequence with strictly monotonically increasing value.

Sample
Input format
The first line contains the integer N.

The second line contains N integers, representing the complete sequence.

Output format
Outputs an integer representing the maximum length.

Data range
1 ≤ N ≤ 1000,
− 1e9 ≤ number in the sequence ≤ 1e9

Input example:

7
3 1 2 1 8 5 6
Output example:

4
Algorithm 1
(dynamic programming) O(n2)O(n2)
Status representation: f[i] represents the largest ascending sequence starting from the first number and ending with w[i]. (the one whose attribute is the maximum in all ascending sequences ending with w[i])

State calculation (set partition): j ∈ (0,1,2,..., i-1), when w [i] > w [j],
f[i] = max(f[i], f[j] + 1).
There is a boundary. If there is no one smaller than I in front, f[i] is 1 (I myself is the end).

Finally, I'm looking for the maximum value of f[i].

Time complexity
O(n2)O(n2) states (nn) * transitions (nn)
C + + code

#include <iostream>

using namespace std;

const int N = 1010;

int n;
int w[N], f[N];

int main() {
    cin >> n;
    for (int i = 0; i < n; i++) cin >> w[i];

    int mx = 1;    // Find out the maximum value of the calculated f[i] and find it while calculating
    for (int i = 0; i < n; i++) {
        f[i] = 1;    // Set f[i] as 1 by default. If the previous number cannot be found, it will be 1
        for (int j = 0; j < i; j++) {
            if (w[i] > w[j]) f[i] = max(f[i], f[j] + 1);    // The previous largest ascending subsequence less than the end of its own number plus itself, i.e. + 1
        }
        mx = max(mx, f[i]);
    }

    cout << mx << endl;
    return 0;
}

Algorithm 2
(dynamic programming + dichotomy) O(nlogn)O(nlogn)
Status representation: f[i] represents the longest ascending subsequence with length I and the smallest number at the end. (among all the endings of the longest ascending subsequence with length I, the min at the end) that is, what is the smallest element at the end of the subsequence with length I.

State calculation: for each w[i], if it is greater than f[cnt-1] (the subscript starts from 0, the longest rising subsequence of CNT length, and the smallest number at the end), then cnt+1, so that the longest rising sequence length + 1, and the current minimum element at the end is w[i]. If w[i] is less than or equal to f[cnt-1], it means that the current length will not be updated, but the minimum element at the end before will change. Find the first one greater than or equal to (here can not be greater than) w[i], and update the minimum element at the end at that time.

f[i] must be a monotonically increasing array, so you can use dichotomy to find the first number greater than or equal to w[i].

Time complexity
O(nlogn)O(nlogn) number of states (nn) * number of transitions (lognlogn)
C + + code

#include <iostream>

using namespace std;

const int N = 1010;
int n, cnt;
int w[N], f[N];

int main() {
    cin >> n;
    for (int i = 0 ; i < n; i++) cin >> w[i];

    f[cnt++] = w[0];
    for (int i = 1; i < n; i++) {
        if (w[i] > f[cnt-1]) f[cnt++] = w[i];
        else {
            int l = 0, r = cnt - 1;
            while (l < r) {
                int mid = (l + r) >> 1;
                if (f[mid] >= w[i]) r = mid;
                else l = mid + 1;
            }
            f[r] = w[i];
        }
    }
    cout << cnt << endl;
    return 0;
}

Author: VictorWu
 Link: https://www.acwing.com/solution/content/4807/
Source: AcWing
 The copyright belongs to the author. For commercial reprint, please contact the author for authorization, and for non-commercial reprint, please indicate the source.

There is also a stack simulation and lower_bound() is simpler and more awesome

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main(void) {
    int n; cin >> n;
    vector<int>arr(n);
    for (int i = 0; i < n; ++i)cin >> arr[i];

    vector<int>stk;//Simulation stack
    stk.push_back(arr[0]);

    for (int i = 1; i < n; ++i) {
        if (arr[i] > stk.back())//If the element is larger than the top element of the stack, put the element on the stack
            stk.push_back(arr[i]);
        else//Replace the first number greater than or equal to this number
            *lower_bound(stk.begin(), stk.end(), arr[i]) = arr[i];
    }
    cout << stk.size() << endl;
    return 0;
}
/*
Example n: 7
arr : 3 1 2 1 8 5 6

stk : 3

1 Smaller than 3
stk : 1

2 Larger than 1
stk : 1 2

1 Smaller than 2
stk : 1 2

8 Larger than 2
stk : 1 2 8

5 Smaller than 8
stk : 1 2 5

6 Bigger than 5
stk : 1 2 5 6

stk The length of is the length of the longest increasing subsequence

*/

Author: 233
 Link: https://www.acwing.com/solution/content/3783/
Source: AcWing
 The copyright belongs to the author. For commercial reprint, please contact the author for authorization, and for non-commercial reprint, please indicate the source.

Longest common subsequence

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
char a[N],b[N];
int dp[N][N];
int n,m;
signed main(){
    cin>>n>>m>>a+1>>b+1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(a[i]==b[j])dp[i][j]=dp[i-1][j-1]+1;
            else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
        }
    }
    cout<<dp[n][m];
}

Given the two strings A and B, now you want to change A into B through several operations. The available operations are:

Delete – deletes A character from string A.
Insert – inserts A character somewhere in string A.
Replace – replaces one character in string A with another.
Now please find out how many operations it takes to change A to B at least.

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
char a[N],b[N];
int dp[N][N];
//dp[i][j] represents the minimum number of operations required for the first I of a to become the first j of b
int n,m;
int minn(int a,int b,int c){
    return min(a,min(b,c));
}
signed main(){
    cin>>n>>a+1>>m>>b+1;
    //entrance
    for(int i=0;i<=n;i++)dp[i][0]=i;//Number of operations required to delete all
    for(int j=0;j<=m;j++)dp[0][j]=j;//Number of operations required for full insertion
    
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(a[i]==b[j])dp[i][j]=dp[i-1][j-1];
            else dp[i][j]=minn(dp[i-1][j-1] , dp[i-1][j] , dp[i][j-1])+1;
                                //Replace insert delete
        }
    }
    //Export
    cout<<dp[n][m];
}
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
char a[N],b[N];
int dp[N][N];
char c[N][11];
int k;
//dp[i][j] represents the minimum number of operations required for the first I of a to become the first j of b
int n,m;
int minn(int a,int b,int c){
    return min(a,min(b,c));
}
int cal(char *a,char*b){
    int n=strlen(a+1);
    int m=strlen(b+1);
    //cout<<n<<m<<endl;
    for(int i=0;i<=n;i++)dp[i][0]=i;//Number of operations required to delete all
    for(int j=0;j<=m;j++)dp[0][j]=j;//Number of operations required for full insertion
    
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(a[i]==b[j])dp[i][j]=dp[i-1][j-1];
            else dp[i][j]=minn(dp[i-1][j-1] , dp[i-1][j] , dp[i][j-1])+1;
                                //Replace insert delete
        }
    }
    return dp[n][m];
}
int solve(){
    cin>>a+1>>k;
    int ans=0;
    for(int i=1;i<=n;i++)
        if(cal(a,c[i])<=k)ans++;
        
    cout<<ans<<endl;
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>c[i]+1;
    while(m--)solve();
    
}

Stone merging

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 330;
int a[N],s[N],f[N][N],n;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        s[i]=s[i-1]+a[i];
    }
    memset(f,0x3f,sizeof f);
    for(int i=0;i<=n;i++)f[i][i]=0;
    
    for(int len=2;len<=n;len++){
        for(int l=1;l+len-1<=n;l++){
            int r=l+len-1;
            for(int k=l;k<r;k++){
                f[l][r]=min(f[l][r] , f[l][k]+f[k+1][r]+s[r]-s[l-1]);
            }
        }
    }
    cout<<f[1][n];
}

Integer partition
Complete knapsack solution
Status indication:

f[i][j]Indicates only from 1~i Selected, and the sum is equal to j Number of schemes

State transition equation:
f[i][j] = f[i - 1][j] + f[i][j - i];

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010, mod = 1e9 + 7;

int n;
int f[N];

int main()
{
    cin >> n;

    f[0] = 1;
    for (int i = 1; i <= n; i ++ )
        for (int j = i; j <= n; j ++ )
            f[j] = (f[j] + f[j - i]) % mod;

    cout << f[n] << endl;

    return 0;
}
Other algorithms
 Status indication:
f[i][j]Indicates that the sum is i,The total number is j Number of schemes

State transition equation:
f[i][j] = f[i - 1][j - 1] + f[i - j][j];

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010, mod = 1e9 + 7;

int n;
int f[N][N];

int main()
{
    cin >> n;

    f[1][1] = 1;
    for (int i = 2; i <= n; i ++ )
        for (int j = 1; j <= i; j ++ )
            f[i][j] = (f[i - 1][j - 1] + f[i - j][j]) % mod;

    int res = 0;
    for (int i = 1; i <= n; i ++ ) res = (res + f[n][i]) % mod;

    cout << res << endl;

    return 0;
}

Author: yxc
 Link: https://www.acwing.com/activity/content/code/content/62496/
Source: AcWing
 The copyright belongs to the author. For commercial reprint, please contact the author for authorization, and for non-commercial reprint, please indicate the source.

Given two integers a and b, find the number of occurrences of 0 ∼ 9 in all numbers between a and b.

For example, if a=1024 and b=1032, there are 9 numbers between a and b as follows:

1024 1025 1026 1027 1028 1029 1030 1031 1032

Among them, 0 appears 10 times, 1 appears 10 times, 2 appears 7 times, 3 appears 3 times, and so on

Input format
The input contains multiple sets of test data.

Each set of test data occupies one line and contains two integers a and b.

When a line 0 is read in, it means that the input is terminated and the line is not processed.

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

const int N = 10;

/*

001~abc-1, 999

abc
    1. num[i] < x, 0
    2. num[i] == x, 0~efg
    3. num[i] > x, 0~999

*/

int get(vector<int> num, int l, int r)
{
    int res = 0;
    for (int i = l; i >= r; i -- ) res = res * 10 + num[i];
    return res;
}

int power10(int x)
{
    int res = 1;
    while (x -- ) res *= 10;
    return res;
}

int count(int n, int x)
{
    if (!n) return 0;

    vector<int> num;
    while (n)
    {
        num.push_back(n % 10);
        n /= 10;
    }
    n = num.size();

    int res = 0;
    for (int i = n - 1 - !x; i >= 0; i -- )
    {
        if (i < n - 1)
        {
            res += get(num, n - 1, i + 1) * power10(i);
            if (!x) res -= power10(i);
        }

        if (num[i] == x) res += get(num, i - 1, 0) + 1;
        else if (num[i] > x) res += power10(i);
    }

    return res;
}

int main()
{
    int a, b;
    while (cin >> a >> b , a)
    {
        if (a > b) swap(a, b);

        for (int i = 0; i <= 9; i ++ )
            cout << count(b, i) - count(a - 1, i) << ' ';
        cout << endl;
    }

    return 0;
}

Author: yxc
 Link: https://www.acwing.com/activity/content/code/content/64211/
Source: AcWing
 The copyright belongs to the author. For commercial reprint, please contact the author for authorization, and for non-commercial reprint, please indicate the source.

Mondrian's dream
Please put N × The chessboard of M is divided into several 1 × How many schemes are there for the rectangle of 2.

For example, when N=2 and M=4, there are five schemes. When N=2 and M=3, there are three schemes.

As shown in the figure below:

2411_1.jpg

Input format
The input contains multiple sets of test cases.

Each set of test cases occupies one line and contains two integers N and M.

When the input case N=0 and M=0, it means that the input is terminated and the case does not need to be processed.

#include<bits/stdc++.h>
using namespace std;
const int N = 12,M=1<<N;
long long dp[N][M];
bool st[M];
int n,m;
signed main(){
    while(cin>>n>>m,n||m){
        for(int i=0;i<1<<n;i++){
            st[i]=1;
            int cnt=0;
            for(int j=0;j<n;j++){
                if(i>>j&1){
                    if(cnt&1){st[i]=0;break;}
                    cnt=0;
                }
                else cnt++;
            }
            if(cnt&1)st[i]=0;
        }
        memset(dp,0,sizeof dp);
        dp[0][0]=1;
        for(int i=1;i<=m;i++){
            for(int j=0;j<1<<n;j++){
                for(int k=0;k<1<<n;k++){
                    if((j&k)==0&&st[j|k])
                    dp[i][j]+=dp[i-1][k];
                }
            }
        }
        cout<<dp[m][0]<<endl;
    }
}

Given a weighted undirected graph with n points labeled from 0 ∼ n − 1, find the shortest Hamilton path from starting point 0 to ending point n − 1.

Hamilton path is defined as passing through each point exactly once from 0 to n − 1.

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 20,M=1<<20;
int w[N][N];
int dp[M][N];
int n;
signed main(){
    cin>>n;
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)cin>>w[i][j];
        
    memset(dp,0x3f,sizeof dp);
    dp[1][0]=0;
    for(int i=0;i<1<<n;i++){
        for(int j=0;j<n;j++){
            if(i>>j&1)
                for(int k=0;k<n;k++){
                    if(i>>k&1)
                    dp[i][j]=min(dp[i][j] , dp[i-(1<<j)][k]+w[k][j]);
                }
        }
    }
    cout<<dp[(1<<n)-1][n-1];
}

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 7000,M=N;
int a[N],n;
int dp[N][2];
int h[N], e[M], ne[M], idx;
void add(int a, int b)  // Add an edge a - > b, and the edge weight is c
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
int rudu[N];

void dfs(int u){
    dp[u][1]=a[u];
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        dfs(j);
        dp[u][1]+=dp[j][0];
        dp[u][0]+=max(dp[j][0],dp[j][1]);
    }
}

signed main(){
    memset(h, -1, sizeof h);
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<n;i++){
        int L,K;
        cin>>L>>K;
        add(K,L);
        rudu[L]++;
    }
    int root=-1;
    for(int i=1;i<=n;i++){
        if(rudu[i]==0){
            root=i;
            break;
        }
    }
    dfs(root);
    cout<<max(dp[root][1],dp[root][0]);
}

Skiing (memory search)

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int a[301][301],dp[301][301];
int n,m;
int xx[]={1,0,-1,0};
int yy[]={0,1,0,-1};
int dfs(int x,int y){
    int &t=dp[x][y];
    if(t)return t;
    for(int i=0;i<4;i++){
        int dx=x+xx[i];
        int dy=y+yy[i];
        if(a[dx][dy]<=a[x][y])continue;
        t=max(t,dfs(dx,dy)+1);
    }
    return t;
}
int main(){
    cin>>n>>m;
    int ans=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++)ans=max(ans,dfs(i,j));
    }
    cout<<ans+1;
}

Trial division
 Time complexity O(T*Root sign n)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int n,t;

bool is_prime(int x){
    if(x<2)return 0;
    for(int i=2;i<=n/i;i++){
        if(n%i==0)return 0;
    }
    return 1;
}

int main(){
    cin>>t;
    while(t--){
        cin>>n;
        if(is_prime(n))puts("Yes");
        else puts("No");
    }
}

Decomposition quality factor

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int T,n;
void divid(int x){
    for(int i=2;i<=x/i;i++){
        if(x%i==0){
            int s=0;
            while(x%i==0)x/=i,s++;
            cout<<i<<" "<<s<<endl;
        }
    }        
    if(x>1)cout<<x<<" "<<1<<endl;

}
signed main(){
    cin>>T;
    while(T--){
        cin>>n;
        divid(n);
        cout<<endl;
    }
}

Given a positive integer n, please find the number of prime numbers in 1 ∼ n.

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e6;
int n;
int st[N],primes[N],cnt;
void get_primes(int n)  // Linear sieve prime number
{
    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;
        }
    }
}

int main(){
    cin>>n;
    get_primes(n);
    cout<<cnt;
}

Try division to find divisor (I use priority queue to save the trouble of sort ing with vector

#include<bits/stdc++.h>
using namespace std;
int x;
priority_queue<int,vector<int>,greater<int>> get_divisors(int x){
    priority_queue<int,vector<int>,greater<int>>q;
    int i=1;
    for(;i<x/i;i++){
        if(x%i==0)q.push(i),q.push(x/i);
    }
    if(i*i==x)q.push(i);
    return q;
}

int main(){
    int T;
    cin>>T;
    while(T--){
        cin>>x;
        auto q=get_divisors(x);
        while(!q.empty()){
            cout<<q.top()<<" ";
            q.pop();
        }
        puts("");
    }
}

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

Definition of Euler function
The number of Coprime numbers with N in 1 ∼ n is called Euler function and is recorded as ϕ (N).
If in the basic theorem of arithmetic, N=pa11pa22... pamm, then:
ϕ(N) = N×p1−1p1×p2−1p2×...×pm−1pm
Input format
The first line contains the integer n.

Next n lines, each containing a positive integer ai.

Output format
A total of n lines are output, and each line outputs an Euler function of a positive integer ai.

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

Find the number of divisors

#include <unordered_map>
#include <iostream>
#include <cstring>
#include <algorithm>
#define hash h
using namespace std;
const int mod=1e9+7;
int x;
int T;
unordered_map<int,int>hash;
int main(){
    cin>>T;
    while(T--){
        cin>>x;
        for(int i=2;i<=x/i;i++){
            while(x%i==0){
                x/=i;
                hash[i]++;
            }
        }
        if(x>1)hash[x]++;
    }
    long long ans=1;
    for(auto t:hash)ans*=(t.second+1);
    cout<<ans;
}

Sum of divisors
algorithm analysis
Basic idea:
If N=p1c1 * p2c2 ∗... * pkckN=p1c1 * p2c2 ∗... * pkck
Number of divisors: (c1+1) * (c2+1) *... * (ck+1)(c1+1) * (c2+1) *... * (ck+1)
Sum of divisors: (p10+p11 +... + p1c1) *... * (pk0+pk1 +... + pkck)(p10+p11 +... + p1c1) *... * (pk0+pk1 +... + pkck)
while (b – ) t = (t * a + 1) % mod;

t=t∗p+1t=t∗p+1
t=1t=1
t=p+1t=p+1
t=p2+p+1t=p2+p+1
......
t=pb+pb−1+...+1
(of course, you can also speed up with a fast power

#include<bits/stdc++.h>
#define hash h
using namespace std;
int T,n;
const int mod=1e9+7;
long long ans=1;
signed main(){
    cin>>T;
    unordered_map<int,int>hash;
    while(T--){
        cin>>n;
        for(int i=2;i<=n/i;i++){
            while(n%i==0){
                n/=i;
                hash[i]++;
            }
        }
        if(n>1)hash[n]++;
    }
    for(auto t:hash){
        int a=t.first;
        int b=t.second;
        long long res=1;
        while(b--)res=(res*a+1)%mod;
        ans=(ans*res)%mod;
    }
    cout<<ans;
}

Given a positive integer n, find the sum of Euler functions of each number in 1 ∼ n.

#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 1000010;

int primes[N], cnt;
int phi[N];
bool st[N];

void get_eulers(int n)
{
    phi[1] = 1;
    for (int i = 2; i <= n; i++)
    {
        if (!st[i])
        {
            primes[cnt++] = i;
            phi[i] = i - 1; 
        }
        for (int j = 0; primes[j] <= n / i; j++)
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0)
            {
                phi[primes[j] * i] = phi[i] * primes[j]; 
                break;
            }
            phi[primes[j] * i] = phi[i] * (primes[j] - 1);
        }
    }
}

int main()
{
    int n;
    cin >> n;

    get_eulers(n);

    LL res = 0;
    for (int i = 1; i <= n; i++) res += phi[i];
    printf("%lld\n", res);

    return 0;
}

Author: ketchup
 Link: https://www.acwing.com/solution/content/3952/
Source: AcWing
 The copyright belongs to the author. For commercial reprint, please contact the author for authorization, and for non-commercial reprint, please indicate the source.
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
int qmi(int a,int b,int q){
    int ans=1;
    while(b){
        if(b&1)ans=(ans*a)%q;
        a=(a*a)%q;
        b/=2;
    }
    return ans;
}
signed main(){
    int t;
    cin>>t;
    while(t--){
        int a,b,p;
        cin>>a>>b>>p;
        cout<<qmi(a,b,p)<<endl;
    }
}

Inverse element

When n When it is a prime number, you can use the fast power to find the inverse element:
a / b ≡ a * x (mod n)
Double multiplication b Available a ≡ a * b * x (mod n)
I.e. 1 ≡ b * x (mod n)
with b * x ≡ 1 (mod n)
From Fermat's small theorem, when n When it is prime
b ^ (n - 1) ≡ 1 (mod n)
Remove one b Come out b * b ^ (n - 2) ≡ 1 (mod n)
So when n When it is a prime number, b Multiplicative inverse of x = b ^ (n - 2)

When n If it is not a prime number, the inverse element can be solved by the extended Euclidean algorithm:
a The necessary and sufficient condition for having an inverse element is a And p Coprime, so gcd(a, p) = 1
 hypothesis a The inverse of is x,So there a * x ≡ 1 (mod p)
Equivalent: ax + py = 1
exgcd(a, p, x, y)

Fast power inverse element
#include <iostream>
using namespace std;
typedef long long LL;

LL qmi(int a, int b, int p)
{
    LL res = 1;
    while(b){
        if(b & 1) res = res * a % p;
        a = (LL)a * a % p;
        b >>= 1;
    }
    return res;
}

int main()
{
    int n; cin >> n;
    while(n --){
        int a, p;
        cin >> a >> p;
        if(a % p == 0) puts("impossible");
        else cout << qmi(a, p - 2, p) << endl;
    }
    return 0;
}
Inverse element of extended Euclidean algorithm
#include <iostream>
using namespace std;
typedef long long LL;
int n;

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()
{
    cin >> n;
    while (n --)
    {
        int a, p, x, y;
        // if (a < p) swap(a, p);
        cin >>  a >> p;
        int d = exgcd(a, p, x, y);
        if (d == 1) cout << ((LL)x + p) % p << endl;//Ensure that x is a positive number
        else puts("impossible");

    }
    return 0;
}


Author: Hz
 Link: https://www.acwing.com/solution/content/3054/
Source: AcWing
 The copyright belongs to the author. For commercial reprint, please contact the author for authorization, and for non-commercial reprint, please indicate the source.

Given n groups of data ai,bi,mi, find a xi for each group to satisfy ai × xi ≡ bi(modmi). If there is no solution, output impossible.

#include <iostream>
#include <algorithm>

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");//If b is not coprime with the common divisor gcd, there is no solution
        else printf("%d\n", (LL)b / d * x % m);
    }

    return 0;-
}

Extended Chinese remainder theorem
Given 2n integers a1,a2,..., an and m1,m2,..., mn, find a minimum nonnegative integer x that satisfies ∀ i ∈ [1,n],x ≡ mi(mod ai).

#include <cstdio>
#include <iostream>
using namespace std;
typedef long long LL;
int n;
LL exgcd(LL a, LL b, LL &x, LL &y){
    if(b == 0){
        x = 1, y = 0;
        return a;
    }

    LL d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}
LL inline mod(LL a, LL b){
    return ((a % b) + b) % b;
}
int main(){
    scanf("%d", &n);
    LL a1, m1;
    scanf("%lld%lld", &a1, &m1);
    for(int i = 1; i < n; i++){
        LL a2, m2, k1, k2;
        scanf("%lld%lld", &a2, &m2);
        LL d = exgcd(a1, -a2, k1, k2);
        if((m2 - m1) % d){ puts("-1"); return 0; }
        k1 = mod(k1 * (m2 - m1) / d, abs(a2 / d));
        m1 = k1 * a1 + m1;
        a1 = abs(a1 / d * a2);
    }
    printf("%lld\n", m1);
    return 0;
}

Author: Mo rankong
 Link: https://www.acwing.com/solution/content/3539/
Source: AcWing
 The copyright belongs to the author. For commercial reprint, please contact the author for authorization, and for non-commercial reprint, please indicate the source.

Gauss elimination for solving linear equations

#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

const int N = 110;
const double eps = 1e-6;

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 = i;

        if (fabs(a[t][c]) < eps) continue;

        for (int i = c; i < n + 1; i ++ ) swap(a[t][i], a[r][i]);
        for (int i = n; i >= c; 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[j][n] * a[i][j];

    return 0;
}

int main()
{
    cin >> n;
    for (int i = 0; i < n; 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("Infinite group solutions");
    else puts("No solution");

    return 0;
}

Gauss elimination for solving XOR linear equations

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 110;


int n;
int 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 (a[i][c])
                t = i;

        if (!a[t][c]) continue;

        for (int i = c; i <= n; i ++ ) swap(a[r][i], a[t][i]);
        for (int i = r + 1; i < n; i ++ )
            if (a[i][c])
                for (int j = n; j >= c; j -- )
                    a[i][j] ^= a[r][j];

        r ++ ;
    }

    if (r < n)
    {
        for (int i = r; i < n; i ++ )
            if (a[i][n])
                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 < n; 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 ++ ) cout << a[i][n] << endl;
    }
    else if (t == 1) puts("Multiple sets of solutions");
    else puts("No solution");

    return 0;
}

Find combination number

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int mod=1e9+7;
int c[2001][2001];
int a,b;

void init(){
    for(int i=0;i<=2000;i++){
        for(int j=0;j<=i;j++){
            if(!j)c[i][j]=1;
            else c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
        }
    }
}

int main(){
    init();
    int T;
    cin>>T;
    while(T--){
        cin>>a>>b;
        cout<<c[a][b]<<endl;
    }
}

Combinatorial number II
When the data range of a and b given is expanded
1≤n≤10000,
1≤b≤a≤105
A fast solution of O(n) time complexity

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

typedef long long LL;

vector<int> getRangeModularMultInv(int n, int p) {
    vector<int> inv(n + 1);
    inv[1] = 1;
    for (int i = 2; i <= n; ++i)
        inv[i] = (LL)(p - p / i) * inv[p % i] % p;
    return inv;
}

const int N = 100010, MOD = 1e9 + 7;
int fac[N], invFac[N];
void calcFac(int n, int m) {
    auto invI = getRangeModularMultInv(n, m);
    fac[0] = 1; invFac[0] = 1;
    for (int i = 1; i < N; i++) {
        fac[i] = (LL)fac[i - 1] * i % m;
        invFac[i] = (LL)invFac[i - 1] * invI[i] % m;
    }
}

int getC(int a, int b, int m) {
    return (LL)fac[a] * invFac[a - b] % m * invFac[b] % m;
}

int main() {
    int q; cin >> q;
    calcFac(N, MOD);
    while (q--) {
        int a, b; cin >> a >> b;
        cout << getC(a, b, MOD) << endl;
    }
    return 0;
}

Author: zan
 Link: https://www.acwing.com/solution/content/22453/
Source: AcWing
 The copyright belongs to the author. For commercial reprint, please contact the author for authorization, and for non-commercial reprint, please indicate the source.
Fast power combination number O(a∗log(mod))O(a∗log(mod))

#include<iostream>
using namespace std;
const int mod=1e9+7,N=1e5+10;
typedef long long LL;
long long fac[N],infac[N];
int quick_pow(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()
{
    int n;
    fac[0]=infac[0]=1;
    for(int i=1;i<=1e5;i++)
    {
        fac[i]=fac[i-1]*i%mod;
        infac[i]=(LL)infac[i - 1] * quick_pow(i,mod-2,mod)%mod;
    }
    cin>>n;
    while(n--)
    {
        int a,b;
        cin>>a>>b;
        cout<<(LL)fac[a] * infac[b] % mod * infac[a - b] % mod<<endl;
        //Cab = factorial of a divided by (factorial of B * (factorial of a-b))
        //Equivalent to a* B inverse element * (a-b) inverse element
    }
}

Author: Code
 Link: https://www.acwing.com/solution/content/22076/
Source: AcWing
 The copyright belongs to the author. For commercial reprint, please contact the author for authorization, and for non-commercial reprint, please indicate the source.

AcWing 887. Finding combinatorial number III(lucas theorem)

Problem solution

#include<iostream>
#include<algorithm>

using namespace std;

typedef long long LL;

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 C(int a,int b,int p)//Argument type int
{
    if(b>a)return 0;//Missing boundary conditions
    int res = 1;
    // a!/(b!(a-b)!) = (a-b+1)*...*a / b!  The molecule has item b
    for(int i=1,j=a;i<=b;i++,j--)//I < = B instead of<
    {
        res = (LL)res*j%p;
        res = (LL)res*qmi(i,p-2,p)%p;
    }
    return res;
}
//Knock on the formula
int lucas(LL a,LL b,int p)
{
    if(a<p && b<p)return C(a,b,p);//lucas recursion end point is C_{bk}^{ak}
    return (LL)C(a%p,b%p,p)*lucas(a/p,b/p,p)%p;//It must be < P after a%p, so you can use C(), but it is not necessarily < P after a/p, so you can continue recursion with lucas
}

int main()
{
    int n;
    cin >> n;
    while(n--)
    {
        LL a,b;
        int p;
        cin >> a >> b >> p;
        cout << lucas(a,b,p) << endl;
    }
    return 0;
}

Author: only honest people remain
 Link: https://www.acwing.com/solution/content/26553/
Source: AcWing
 The copyright belongs to the author. For commercial reprint, please contact the author for authorization, and for non-commercial reprint, please indicate the source.


Someone has simply optimized the C(a,b,p) function, and the board is 10 times faster than yxc

#include <iostream>
#include <cstring>

using namespace std;

typedef long long LL;

const int N = 100010, 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 C(int a, int b, int p)
{
    if(a < b)return 0;
    int down = 1, up = 1;
    for(int i=a, j=1; j<=b; i--, j++)
    {
        up = (LL)up * i % p;
        down = (LL)down * j % p;
    }

    return (LL)up * qmi(down, p-2, p) % p;
}

int lucas(LL a, LL b, int p)
{
    if(a<p && b<p)return C(a, b, p);
    else return (LL)C(a%p, b%p, p)*lucas(a/p, b/p, p)%p;
}

int main()
 {

    int n;
    scanf("%d", &n);
    while(n--)
    {
        LL a, b, p;
        cin>>a>>b;
        cin>>p;
        cout<<lucas(a, b, p)<<endl;
     }

    return 0;
 }


Find the combination number Ⅳ
No mod p, the results should be calculated with high precision

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;


const int N = 5010;

int primes[N], cnt;
int sum[N];
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;
        }
    }
}


int 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;
    int t = 0;
    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;
    cin >> a >> b;

    get_primes(a);

    for (int i = 0; i < cnt; i ++ )
    {
        int p = primes[i];
        sum[i] = get(a, p) - get(a - b, p) - get(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;
}

Author: yxc
 Link: https://www.acwing.com/activity/content/code/content/53401/
Source: AcWing
 The copyright belongs to the author. For commercial reprint, please contact the author for authorization, and for non-commercial reprint, please indicate the source.

01 sequence satisfying conditions
Put the problem in the coordinate system to solve

#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;


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 C(int a, int b, int p)
{
    if (b > a) return 0;

    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) % p;
    }
    return res;
}


int lucas(LL a, LL b, int p)
{
    if (a < p && b < p) return C(a, b, p);
    return (LL)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;
}


int main()
{
    int n;
    cin >> n;

    while (n -- )
    {
        LL a, b;
        int p;
        cin >> a >> b >> p;
        cout << lucas(a, b, p) << endl;
    }

    return 0;
}

Author: yxc
 Link: https://www.acwing.com/activity/content/code/content/53399/
Source: AcWing
 The copyright belongs to the author. For commercial reprint, please contact the author for authorization, and for non-commercial reprint, please indicate the source.

Train in and out of the stack (classical application of Katra number)
A train has n carriages, numbered 1,2,3,..., n1,2,3,..., n.

There are two movement modes for each carriage, entering and leaving the stack. Ask how many possible arrangement modes for n carriages to leave the stack.
This problem is also to find Cartland number. The difference is that this problem requires high precision and card time

#include <stdio.h>

const int N = 11311;
const int base = 1e9;  // Press 9
const int basebit = 9;

int n;
int sum[N];             // Save the results of screened prime numbers and their times
long long res[4500];    // Save the answer, res[0] save the number of digits of res
int primes[N], cnt;     // Prime number of stored sieve
bool st[120001];        // bool array for screening prime numbers

inline void init()      // Linear sieve prime number + result of solving decomposition prime factor
{
    for (register int i = 2; i <= n << 1; i ++ )
    {
        if (!st[i])     // If st[i] == false, the number I is prime
        {
            primes[ ++ cnt] = i; // Save it in primes first
            for (register int j = (n << 1) / i; j; j /= i) // Add (2n)! Quantity containing i.
                sum[cnt] += j;
            for (register int j = n / i; j; j /= i) // Subtract (n!)^2 quantity containing i.
                sum[cnt] -= j << 1; // (n!)^2 contains the number of i, that is, twice the number of n! The number of i contained, so only n!, Then subtract twice the quantity it contains
            for (register int j = n + 1; j % i == 0; j /= i) // Subtract the quantity of n + 1 containing i
                sum[cnt] -- ;
        }
        for (register int j = 1; primes[j] <= (n << 1) / i; j ++ ) // Plate of linear sieve
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break ;
        }
    }
}

inline int qmi(int a, int b) // Fast exponentiation (actually not useful). Most calls will go into that if (b == 1).. Therefore, a special judgment is added to improve the efficiency.)
{
    if (b == 1) return a;
    int res = 1;
    for (; b; a *= a, b >>= 1)
        if (b & 1) res *= a;
    return res;
}

inline void multi(int b)     // Multiply res by b
{
    register long long t = 0;
    for (register int i = 1; i <= res[0]; i ++ )
    {
        res[i] = res[i] * b + t;
        t = res[i] / base;
        res[i] %= base;
    }
    while (t) res[ ++ res[0]] = t % base, t /= base;
}

void print(int x, int i = basebit) // Fast output 9 bits
{
    if (!i) return ;
    print(x / 10, i - 1);
    putchar(x % 10 ^ 48);
}

int main()
{
    scanf("%d",&n);
    init();              // Initialize primes + initialize sum
    res[0] = res[1] = 1; // Initialize res, the length of res is 1, and the value of res is 1
    for (register int i = 1; i <= cnt; i ++ ) // Enumerate all the prime numbers decomposed
        if (sum[i]) multi(qmi(primes[i], sum[i]));
    printf("%lld", res[res[0]]);              // The first bit does not output 9 bits
    if (res[0] > 1)      // If the number of bits of res is greater than one, the following is output
        for (register int i = res[0] - 1; i; i -- )
            print(res[i]);
    return 0;
}

Author: bottom suction
 Link: https://www.acwing.com/solution/content/15603/
Source: AcWing
 The copyright belongs to the author. For commercial reprint, please contact the author for authorization, and for non-commercial reprint, please indicate the source.
import math

n = int(input())
A = math.factorial(2 * n)
B = math.factorial(n)
print(A // B // B // (n + 1))

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

Please find out how many integers in 1 ∼ n can be divided by at least one number in p1,p2,..., pm.

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long 
int primes[16];
int ans=0;
signed main(){
    int n,m;
    cin>>n>>m;
    for(int i=0;i<m;i++)cin>>primes[i];
    
    //i is wrong from 0 and right from 1
    //This is also to ensure that the inclusion exclusion principle calculates at least one graph
    for(int i=1;i<1<<m;i++){
        int t=1,cnt=0;
        for(int j=0;j<m;j++){
            if(i>>j&1){
                if(primes[j]*t>n){
                    t=-1;
                    break;
                }
                t*=primes[j];
                cnt++;
            }
        }
        if(t==-1)continue;
        
        if(cnt&1)ans+=n/t;
        else ans-=n/t;
    }
    cout<<ans;
}

Chinese remainder theorem

#include<bits/stdc++.h>
using namespace std;
#define int long long
int mod(int a,int b){
    return (a%b+b)%b;
}
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;
}
signed main(){
    int n;
    cin>>n;
    int a1,m1,k1;
    cin>>a1>>m1;
    for(int i=1;i<n;i++){
        int a2,m2,k2;
        cin>>a2>>m2;
        int d=exgcd(a1,-a2,k1,k2);
        if((m2-m1)%d){puts("-1");return 0;}
        k1=mod(k1*(m2-m1)/d , abs(a2/d));
        m1=m1+k1*a1;
        a1=abs(a1/d*a2);
    }
    cout<<m1;
    
}

If a game meets:

Two players act alternately
At any moment in the game, the legal actions that can be performed have nothing to do with who is the player's turn
Players who can't act are judged negative
The game is called a fair combination game.

Nim game (NIM) is a fair combination game, but common chess games, such as go, are not fair combination games, because the warring sides of go can only drop sunspots and whites respectively, and the judgment of victory and defeat is also more responsible, which does not meet conditions 2 and 3.

Title Description
Given a nn pile of stones, two players operate in turn. Each operation can take any number of stones from any pile of stones (you can take them all, but you can't take them away). Finally, the person who can't operate is regarded as a failure.
If both of them adopt the optimal strategy, will they win first.

For example, there are two piles of stones, two in the first pile and three in the second pile. The first hand will win.

Operation steps:

  1. Take one from the second pile first. At this time, the number of the first pile and the second pile are the same
  2. No matter how the back hand takes it, the first hand can take the same number of stones from another pile of stones.

Winning state and losing state
Before solving this problem, let's understand two nouns:

Winning state: when the first hand performs an operation and leaves the second hand a losing state, it is a winning state for the first hand. That is, the first hand can go to a certain state of failure.
Must lose state: when the first hand operates anyway and leaves the second hand a must win state, it is a must lose state for the first hand. That is, you can't go to any state of failure first.
conclusion
Suppose nn piles stones, and the number of stones is a1,a2,..., ana1,a2,..., an respectively. If A1 ⊕ a2 ⊕... ⊕ an ≠ 0a1 ⊕ a2 ⊕... ⊕ an ≠ 0, the first hand will win; Otherwise, you will lose first.

  1. If the situation faced by the forerunner is A1 ⊕ a2 ⊕... ⊕ an ≠ 0a1 ⊕ a2 ⊕... ⊕ an ≠ 0, the forerunner can always take a pile of stones and turn the situation into A1 ⊕ a2 ⊕... ⊕ an=0a1 ⊕ a2 ⊕... ⊕ an=0. If you repeat this, you must be faced with the situation that there are no stones to take in the end. First hand wins.
  2. If the situation faced by the first hand is A1 ⊕ a2 ⊕... ⊕ an=0a1 ⊕ a2 ⊕... ⊕ an=0, no matter how the first hand takes it, it will turn the situation into A1 ⊕ a2 ⊕... ⊕ an ≠ 0a1 ⊕ a2 ⊕... ⊕ an ≠ 0, then the second hand can always take a pile of stones and turn the situation into A1 ⊕ a2 ⊕... ⊕ an=0a1 ⊕ a2 ⊕... ⊕ an=0. If you repeat this, you must be the first to face the situation that there are no stones to take in the end. If you start first, you will lose.
#include<bits/stdc++.h>
using namespace std;
int n;
signed main(){
    cin>>n;
    int ans=0;
    while(n--){
        int x;
        cin>>x;
        ans^=x;
    }
    if(ans==0)puts("No");
    else puts("Yes");
}

Now, there is a staircase with n steps, and there are several stones on each step, of which there are ai stones on the i-th step (I ≥ 1).

The two players operate in turn. Each operation can take several stones from any step and put them in the next step (you can't do without them).

The stone that has been taken on the ground cannot be taken again, and the person who is unable to operate at last is regarded as a failure.

If both of them adopt the optimal strategy, will they win first.
(the core is: the first hand always leaves the odd step XOR 0 state to the opposite, that is, always gives the inevitable state to the opposite)

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int n;
signed main(){
    cin>>n;
    int ans=0;
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        if(i&1)ans^=x;
    }
    if(ans)puts("Yes");
    else puts("No");
}
#include<bits/stdc++.h>
using namespace std;
const int N = 110,M=10010;
int n,m;
int s[N],SG[M];
int sg(int x){
    if(SG[x]!=-1)return SG[x];
    unordered_set<int>S;
    for(int i=0;i<m;i++){
        if(x>=s[i])S.insert(sg(x-s[i]));
    }
    for(int i=0;;i++){
        if(!S.count(i))return SG[x]=i;
    }
}
signed main(){
    memset(SG,-1,sizeof SG);
    cin>>m;
    for(int i=0;i<m;i++)cin>>s[i];
    cin>>n;
    int ans=0;
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        ans^=sg(x);
    }
    if(ans)puts("Yes");
    else puts("No");
}
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_set>
using namespace std;
const int N = 110;
int f[N];
int n;
int sg(int x){
    if(f[x]!=-1)return f[x];
    unordered_set<int>S;
    for(int i=0;i<x;i++){
        for(int j=0;j<=i;j++){
            S.insert(sg(i)^sg(j));
        }
    }
    //mex operation: find the minimum natural number that does not exist in the set
    for(int i=0;;i++){
        if(!S.count(i))return f[x]=i;
    }
}
signed main(){
    cin>>n;
    memset(f,-1,sizeof f);
    int ans=0;
    while(n--){
        int x;
        cin>>x;
        ans^=sg(x);
    }
    if(ans)puts("Yes");
    else puts("No");
}

Interval grouping

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
struct node{
    int l,r;
    bool operator<(const node&t){
        return l<t.l;
    }
}range[N];
signed main(){
    int n;
    cin>>n;
    for(int i=0;i<n;i++)cin>>range[i].l>>range[i].r;
    priority_queue<int,vector<int>,greater<int>>heap;
    sort(range,range+n);
    for(int i=0;i<n;i++){
        if(heap.empty()||range[i].l<=heap.top())heap.push(range[i].r);
        else{
            heap.pop();
            heap.push(range[i].r);
        }
    }
    cout<<heap.size();
}

Topics: C++ Algorithm Dynamic Programming