Special topic of mathematics in HENAU winter camp

Posted by sarah on Mon, 17 Jan 2022 05:12:14 +0100

Title Link: Portal
Title password: 202201150000
Data connection:
Counting
Inverse element
Inclusion exclusion principle
Extended Euclid
Learning the game of taking stones in game theory
Title Content:

Here is the reference

mathematical problem

A - A^B Mod C

Idea: this topic can think of violence first, but the data is too large, so it is unrealistic. Therefore, use fast power to solve it. See the above link for details
code:

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef pair<ll,ll> P;
const int maxn=100100;
const int inf=0x3f3f3f3f3f;
const int maxm=5e4+5;
const int mod=1000000007;
//ll a,b,c;
ll pmod(ll a,ll b,ll c){
    ll ans=1;
    while(b){

        if(b&1)ans=(ans*a)%c;
        b>>=1;
        a=a*a%c;
        //cout<<a<<endl;
    }
    return ans;
}
int main(){
    ll a,b,c;
    cin>>a>>b>>c;
    cout<<pmod(a,b,c);
    return 0;
}

B - inverse element

Idea: it directly solves the inverse element, but it times out. Just look at the online solution. The link is as follows: Problem solution
code:

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef pair<ll,ll> P;
const int maxn=1e9;
const int inf=0x3f3f3f3f3f;
const int maxm=5e4+5;
const int mod=1000000007;
//ll a,b,c;
ll n;
map<ll,ll> in;

bool isprime(ll x)
{
    for(ll i=2;i*i<=x;i++)
    {
        if(x%i==0)
            return false;
    }
    return true;
}

int main(){
    cin>>n;
    if(!isprime(n)){
        cout<<"AKCniubi"<<endl;
    }
    else{
        cout<<n*(n-1)/2;
    }
    return 0;
}

C - number of decision primes

Idea: know how to judge whether a number is a prime number. The prime sieve used here is not sure which of x and y is bigger or smaller
code:

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef pair<ll,ll> P;
const int maxn=1e5+10;
const int inf=0x3f3f3f3f3f;
const int maxm=5e4+5;
const int mod=1000000007;
//ll a,b,c;
ll n;
ll pri[maxn+10],v[maxn+10];
ll m;
void prime(){
    v[1]=1;
    for(int i=2;i<=maxn;i++){
        if(v[i]==0){
            v[i]=i;
            m++;
            pri[m]=i;
            //cout<<i<<endl;
        }
        for(int j=1;j<=m&&(i*pri[j]<=maxn);j++){
            v[i*pri[j]]=pri[j];
            if(i%pri[j]==0)break;
        }
        //cout<<i<<endl;
    }
}
int main(){
    prime();
    ll x,y;
    scanf("%lld%lld",&x,&y);
    if(x>y){
        ll t=x;
        x=y;
        y=t;
    }
    ll ans=0;
    for(int i=x;i<=y;i++){
        if(v[i]==i&&i!=1){
            ans++;
            //cout<<i<<" ";
        }
    }
    printf("%lld\n",ans);
    return 0;
}

D - matrix multiplication

Idea: understand matrix multiplication
code:

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef pair<ll,ll> P;
const int maxn=1e5+10;
const int inf=0x3f3f3f3f3f;
const int maxm=5e4+5;
const int mod=1000000007;
ll n,m,k;
ll a[110][110],b[110][110],d[110][110];
int main(){
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
        }
    }
    for(int i=1;i<=m;i++){
        for(int j=1;j<=k;j++){
            cin>>b[i][j];
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=k;j++){
            for(int h=1;h<=m;h++){
                d[i][j]+=a[i][h]*b[h][j];
            }
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=k;j++){
            cout<<d[i][j]<<" ";
        }
        cout<<endl;
    }

    return 0;
}

H - number of Coprime numbers (I)

Idea: first, understand the concept of Coprime, and then use Euler function to find the result
Derivation process:
Euler formula: phi(x) = (p1-1)/p1*(p2-1)/p2... (pn-1)/pn * x
The derivation process is as follows:
X = P1 ^ K1, p2k2 *... pnkn, for a number m=a^b(a is a prime number), the number that is not coprime with m has only a multiple of a, i.e. m/a, i.e. a ^ (b-1), so the number that is coprime with m is m-m/a=a ^ b-a^(b-1);
Similarly,
phi(x)=[p1^ k1-p1^(k1-1)] * [p2^ k2-p2^ (k2-1)]......[pn ^ kn-pn^(kn-1)]
=[p1^(k1-1) * (p1-1)] * [p2^(k2-1)(p2-1)]......* [pn^(kn-1)*(pn-1)]
=[p1^ (k1-1) * p2^ (k2-1)......pn^(kn-1)][(p1-1) * (p2-1) * ...... * (pn-1)]
=x * [(p1-1) * (p2-1)... * (pn-1)]/[(p1-1) * (p2-1) * ...... *(pn-1)]
code:

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef pair<ll,ll> P;
const int maxn=1e5+10;
const int inf=0x3f3f3f3f3f;
const int maxm=5e4+5;
const int mod=1000000007;
ll t;
ll solve(ll n){
        ll ans=n;
        for(ll i=2;i*i<=n;i++){
            if(n%i==0){
                ans=ans/i*(i-1);
                for(;n%i==0;n/=i);
            }
        }
        if(n!=1){
            ans=ans/n*(n-1);
        }
        return ans;
}
int main(){
    scanf("%lld",&t);
    ll n;
    while(t--){
        scanf("%lld",&n);

        printf("%lld\n",solve(n));
    }
    return 0;
}

I - Sumdiv

Idea:
Divisor and formula:
For decomposed integers, A=(p1 ^ k1) * (p2 ^ k2) * (p3 ^ k3)... * (pn^kn)
The sum of all factors with A is
S = (1+p1+p1 ^ 2+p1 ^ 3+...p1^k1) * (1+p2+p2 ^ 2+p2 ^ 3+....p2^k2) * (1+p3+ p3 ^ 3+...+ p3^k3) * ... * (1+pn+pn ^ 2+pn ^ 3+...pn^kn)
Calculation of equal ratio sequence: directly use bisection recursion: for example, 1+a+a ^ 2+a ^ 3+a ^ 4=(1+a) * (1+a2)+a2;(1+a)=1(1+a). Divide it in half according to parity. As long as there is only one number.
code:

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef pair<ll,ll> P;
const int maxn=1e5+10;
const int inf=0x3f3f3f3f3f;
const int maxm=5e4+5;
const int mod=9901;
ll n,m;
struct node{
    ll x,y;
}p[maxn];
ll pmod(ll x,ll y){
    ll res=1;
    while(y){
        if(y&1){
            res=res*x%mod;
        }
        x=x*x%mod;
        y>>=1;
    }
    return res;
}
ll update(ll pn,ll pm){
    //cout<<pm<<endl;
    if(pm==0){
        return 1;
    }
    if(pm&1){
        return update(pn,pm/2)*(1+pmod(pn,pm/2+1))%mod;
    }else{
        return (update(pn,pm/2-1)*(1+pmod(pn,pm/2+1))+pmod(pn,pm/2))%mod;
    }
}
int main(){
    while(scanf("%lld%lld",&n,&m)!=EOF){
        ll k=0;
        for(int i=2;i*i<=n;){
            if(n%i==0){
                k++;
                p[k].x=i;
                p[k].y=0;
                while(n%i==0){
                    p[k].y++;
                    n/=i;
                }
            }
            if(i==2){
                i++;
            }else{
                i+=2;
            }
        }
        if(n!=1){
            k++;
            p[k].x=n;
            p[k].y=1;
        }
        ll ans=1;
        //cout<<ans<<endl;
        for(int i=1;i<=k;i++){
            ans=(ans*update(p[i].x,p[i].y*m)%mod)%mod;
            //cout<<ans<<endl;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

J - The Lottery

Idea: use binary to enumerate all cases, and use the principle of tolerance and exclusion to remove duplication. Among them, consider the opposite side. There are n/a multiples of a; It is not only a, but also a multiple of B, that is, the multiple of lcm(a,b) has n/lcm(a,b). Is the multiple of a,b,c, i.e. the multiple of lcm(a,b,c) has n/lcm(a,b,c).
code:

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef pair<ll,ll> P;
const int maxn=1e5+10;
const int inf=0x3f3f3f3f3f;
const int maxm=5e4+5;
const int mod=9901;
ll t,k,n,m;
ll a[maxn];
ll gcd(ll a,ll b){
    return b ? gcd (b,a%b) : a;
}
ll lcm(ll a,ll b){
    ll t=gcd(a,b);
    return a/t*b;
}
int main(){
    while(cin>>n>>m){
        for(int i=0;i<m;i++){
            cin>>a[i];
        }
        ll sum=0;
        for(int i=1;i<(1<<m);i++){//Enumerate all cases
            ll cnt=0;
            ll ans=1;
            for(int j=0;j<m;j++){
                if(i&(1<<j)){
                    ans=lcm(ans,a[j]);
                    if(ans>n){
                        break;
                    }
                    cnt++;
                }
            }
            if(cnt&1){
                sum+=n/ans;
            }else{
                sum-=n/ans;
            }
        }
        cout<<n-sum<<endl;
    }
    return 0;
}

K - combinatorial number problem

Idea: first, preprocess to prevent timeout. Understand the operation of combinatorial numbers, that is, C(n,m)=C(n-1,m-1)+C(n-1,m), and then simple dynamic programming
code:

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef pair<ll,ll> P;
const int maxn=1e5+10;
const int inf=0x3f3f3f3f3f;
const int maxm=5e4+5;
const int mod=9901;
ll t,k;
ll n,m;
ll a[2010][2010],num[2010][2010];
void init(){
    a[1][1]=1%k;
    if(a[1][1]==0)num[1][1]=1;
    for(int i=2;i<2001;i++){
        a[i][1]=i%k;
        if(a[i][1]==0)num[i][1]=1;
        for(int j=2;j<=i;j++){
            a[i][j]=(a[i-1][j-1]+a[i-1][j])%k;
            if(a[i][j]==0){
                num[i][j]=num[i][j-1]+1;
            }else{
                num[i][j]=num[i][j-1];
            }
        }
    }
}
int main(){
    cin>>t>>k;
    init();
    while(t--){
        cin>>n>>m;
        int ans=0;
        for(int i=1;i<=n;i++){
            ll t=i;
            if(m<i){
                t=m;
            }
            ans+=num[i][t];
        }
        cout<<ans<<endl;
    }
    return 0;
}

L - congruence equation

Idea: ax ≡ 1(modb) can be changed to get ax+kb=gcd(a,b), because there must be a solution, which is the result of the extended Euclidean principle
code:

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef pair<ll,ll> P;
const int maxn=1e5+10;
const int inf=0x3f3f3f3f3f;
const int maxm=5e4+5;
const int mod=9901;
ll a,b,x=0,y=0;
void exgcd(ll a,ll b,ll &x,ll &y){
    if(!b){
        x=1,y=0;
    }else{
        exgcd(b,a%b,x,y);
        ll t;
        t=x,x=y,y=t-a/b*y;
    }
}
int main(){
    cin>>a>>b;
    exgcd(a,b,x,y);
    cout<<(x%b+b)%b;
    return 0;
}

Game problem

E - Bash games

Idea:
1. N < = k, a must win, n=k+1,B must win
2. When K + 1 < n < = (2k+1), A only needs to take n-(k+1) (must be less than or equal to k), and A must win
3. When n = 2 (K + 1), no matter how many A takes, suppose x. at this time, N-x > = K + 2, B only needs to take (n-x-(k+1)) and B must win
4. And so on
code:

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef pair<ll,ll> P;
const int maxn=1e5+10;
const int inf=0x3f3f3f3f3f;
const int maxm=5e4+5;
const int mod=1000000007;
ll n,k;
//B n==k+1
//A n<=k
int main(){
    ll t;
    cin>>t;
    while(t--){
        cin>>n>>k;
        if(n%(k+1)){
            cout<<"A"<<endl;
        }else{
            cout<<"B"<<endl;
        }
    }
    return 0;
}

F - stone game

Idea: it belongs to wythoff game
code:

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef pair<ll,ll> P;
const int maxn=1e5+10;
const int inf=0x3f3f3f3f3f;
const int maxm=5e4+5;
const int mod=1000000007;
ll n,k;
//A 1 1
//B 2 1;
double x = (sqrt(5.0) + 1)/2.0;
int main(){
    ll a,b;
    while(cin>>a>>b){
        ll t=abs(b-a);
        if(a>b){
            ll k=a;
            a=b;
            b=a;
        }
        if((int)(t*x)==a){
            cout<<"0"<<endl;
        }else{
            cout<<"1"<<endl;
        }
    }
    return 0;
}

G - Matches Game

Idea: when the XOR and are odd, take it first. After taking it, no matter how you take it, the first hand must take it the same as the second hand, and you can get the last. When the XOR and are even, no matter how the first hand takes it, the second hand just needs to take the same, and you can get the last
code:

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef pair<ll,ll> P;
const int maxn=1e5+10;
const int inf=0x3f3f3f3f3f;
const int maxm=5e4+5;
const int mod=1000000007;
ll n;
int main(){
    while(cin>>n){
        ll ans=0;
        for(int i=1;i<=n;i++){
            ll x;
            cin>>x;
            ans=ans^x;
        }
        //cout<<ans<<endl;
        if(ans){
            cout<<"Yes"<<endl;
        }else{
            cout<<"No"<<endl;
        }
    }
    return 0;
}

Topics: Algorithm Dynamic Programming linear algebra