18寒假的数论

1.容斥原理找1到M中与N互质的数

int primes[33], ptot;
vector<pair<int,int> > split(int n) {
    vector<pair<int,int> > stk;
    for(int i = 2; i * i <= n; i++) {
        if(n % i == 0) {
            stk.push_back(make_pair(i, 0));//一维表示因子,二维表示个数
            while(n % i == 0) {
                n /= i;
                stk.back().second++;
            }
        }
    }
    if(n != 1) {
        stk.push_back(make_pair(n, 1));//特判
    }
    return stk;
}

void print(int s) {
    for(int i = 7; i >= 0; i--)
        printf("%d", (s>>i)&1);
    printf("\n");
}

void subset(int u) {
//    int u = 0x5;    //0x5 = 5    0000 0101
    for(int s = u; s; s = (s - 1) & u) {
        print(s);
    }
    print(0);
}
*/

#include <vector>
#include <cstdio>
#include <algorithm>
using namespace std;

int countbits(int s) {
    int rt = 0;
    while(s) {
        rt++;
        s -= s & -s;
    }
    return rt;
}
int count(int m, int n) {
    vector<int> stk;
    for(int i = 2; i * i <= n; i++) {
        if(n % i == 0) {
            stk.push_back(i);
            while(n % i == 0)
                n /= i;
        }
    }
    if(n != 1) stk.push_back(n);
    if(stk.size() == 0) return 1;
    int rt = 0;
    int u = (1<<stk.size()) - 1;//造全集
    for(int s = u; s; s = (s - 1) & u) {//造子集
        int mul = 1;
        for(int t = 0; t < (int)stk.size(); t++)
            if((s>>t) & 1) mul *= stk[t];
        if(countbits(s) & 1) //奇加偶减
            rt += m / mul;
        else
            rt -= m / mul;
    }
    return m - rt;
}

int main() {
    while(1) {
        int m, n;
        scanf("%d%d", &m, &n);
        printf("%d\n", count(m,n));
    }
}

2.矩阵快速幂

主要分清单位矩阵和初始矩阵以及向量之间的关系

#include <bits/stdc++.h>

using namespace std;
#define ll long long
ll a0,a1,a2,b,c,d,e,n;
const ll M = 1000000000000000000LL;
struct Maxtri{
    ll w[4][4];
    void unit() {//单位矩阵
        for(int i = 0; i < 4; i++)
            for(int j = 0; j < 4; j++)
                w[i][j] = (i == j);
    }
    ll *operator[](int i){
        return w[i];
    }
};
ll add(ll a,ll b){
    ll c = a + b;
    if(c >= M)c -= M;
    return c;
}
ll quick(ll a,ll b){
    ll rt = 0;
    for(;b;b>>=1,a=add(a,a))
        if(b & 1)rt=add(a,rt);
    return rt;
}
Maxtri operator*(Maxtri l, Maxtri r){
    Maxtri c;
    for(int i = 0; i < 4; i++)
        for(int j = 0; j < 4; j++){
            c[i][j] = 0;
            for(int k = 0; k < 4; k++)
            c[i][j] = add( c[i][j] , quick(l[i][k], r[k][j]) );
        }
    return c;

}
Maxtri mul(ll b, Maxtri a){
    Maxtri rt;
    for(rt.unit(); b; b>>=1, a=a*a)
        if(b & 1) rt = rt*a;
    return rt;

}
int main(){
    //freopen("seq.in","r",stdin);
    //freopen("seq.out","w",stdout);
    scanf("%I64d%I64d%I64d%I64d%I64d%I64d%I64d%I64d",&a0,&a1,&a2,&b,&c,&d,&e,&n);
    Maxtri a;
    for(int i = 0; i < 4; i++)
        for(int j = 0; j < 4; j++)
            a[i][j] = 0;
    a[2][0] = d, a[2][1] = c, a[2][2] = b, a[2][3] = e;
    a[0][1] = a[1][2] = a[3][3] = 1;//初始矩阵
    Maxtri q = mul(n, a);
    Maxtri p;
    p[0][0] = a0, p[0][1] = a1, p[0][2] = a2,p[0][3] = 1;//向量
    ll ans = 0;
    for(int i = 0; i < 4; i++)
           ans = add(ans, quick( q[0][i] , p[i][0] ));//最后点乘向量
    stringstream ss;
    string sans;
    ss << ans;
    ss >> sans;
    for(int i = 1; i < 18 - (int)sans.size(); i++)
        printf("0");
    cout<<sans<<endl;
    return 0;
}

再贴一个板子

const int Mod = 1e9 + 7;

struct Matrix {
    int w[2][2];
    void zero() {
        for(int i = 0; i < 2; i++)
            for(int j = 0; j < 2; j++)
                w[i][j] = 0;
    }
    void unit() {//构造单位矩阵,不是初始矩阵
        for(int i = 0; i < 2; i++)
            for(int j = 0; j < 2; j++)
                w[i][j] = (i == j);
    }
    int *operator[](int i) {//重载【】
        return w[i];
    }
};

Matrix operator*(const Matrix &r, const Matrix &s) {//重载乘号
    Matrix c;
    for(int i = 0; i < 2; i++)
        for(int j = 0; j < 2; j++) {
            c[i][j]  = 0;
            for(int k = 0; k < 2; k++)
                c[i][j] = (c[i][j] + 1LL * r[i][k] * s[k][j])% Mod;
        }
    return c;
}

Matrix mpow(Matrix a, int b) {//矩阵快速幂
    Matrix rt;
    for(rt.unit(); b; b>>=1,a=a*a)
        if(b & 1) rt=rt*a;
    return rt;
}

然后是数论代码板子了→

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

const int N = 1000100;

namespace NT {
bool isnot[N];
int mu[N], phi[N];
int primes[N], ptot;
//筛素数
void normal_sieve( int n ) {
    isnot[1] = true;
    for( register int i = 2; i <= n; i++ ) {
        if( !isnot[i] ) {
            for( register int j = i + i; j <= n; j += i ) {
                isnot[j] = true;
            }
        }
    }
}
void linear_sieve( int n ) {
    isnot[1] = true;
    for( int i = 2; i <= n; i++ ) {
        if( !isnot[i] ) //isnot是合数
            primes[ptot++] = i;
        for( int t = 0; t < ptot; t++ ) {
            int j = primes[t] * i;
            if( j > n ) break;
            isnot[j] = true;
            if( i % primes[t] == 0 )
                break;
        }
    }
}
void linear_sieve_more( int n ) {
    isnot[1] = true;
    mu[1] = 1;
    phi[1] = 1;
    for( int i = 2; i <= n; i++ ) {
        if( !isnot[i] ) {
            primes[ptot++] = i;
            mu[i] = -1;
            phi[i] = i - 1;
        }
        for( int t = 0; t < ptot; t++ ) {
            int j = primes[t] * i;
            if( j > n ) break;
            isnot[j] = true;
            mu[j] = mu[primes[t]] * mu[i];
            phi[j] = phi[primes[t]] * phi[i];
            if( i % primes[t] == 0 ) {
                mu[j] = 0;
                phi[j] = primes[t] * phi[i];
                break;
            }
        }
    }
}

//    greatest common divisor
long long gcd( long long a, long long b ) {
    return b == 0 ? a : gcd( b, a % b );
}

long long lcm( long long a, long long b ) {
    return a / gcd(a,b) * b;//先除后乘
}

//    gcd(a,b) = a * x + b * y
long long exgcd( long long a, long long b, long long &x, long long &y ) {
    if( b == 0 ) {
        x = 1;
        y = 0;
        return a;
    } else {
        long long x0, y0;
        long long cd = exgcd( b, a % b, x0, y0 );
        x = y0;
        y = x0 - (a/b) * y0;
        return cd;
    }
}
int main() {
    int a, b;
    while( scanf("%d%d",&a,&b) == 2 ) {
        long long x, y;
        long long cd = exgcd(a,b,x,y);
        printf( "%lld = %d * %lld + %d * %lld\n", cd, a, x, b, y );
    }
}

//    ax + by = c
bool linear_equation( long long a, long long b, long long c, long long &x, long long &y, long long &xinc, long long &yinc ) {
    long long d = gcd(a,b);
    if( c % d != 0 ) return false;
    a /= d, b /= d, c /= d;
    exgcd( a, b, x, y );
    x *= c;
    y *= c;
    xinc = b;
    yinc = -a;
    return true;
}

//    lucas‘t theorem
//    C(n,m) = C(n / p, m / p) * C(n % p, m % p) ( mod p )    when 0 <= m <= n
//    C(n,m) = 0 ( mod p )    when m > n
long long fac[N], vfac[N];
// 求组合数
/* 暴力
long long comb[N][N];

void init(int n) {
    for(int i = 0; i <= n; i++) {
        for(int j = 0; j <= i; j++) {
            if(j == 0 || j == i)
                comb[i][j] = 1;
            else
                comb[i][j] = (comb[i-1][j-1] + comb[i-1][j]) % Mod;
        }
    }
}
*/
//公式
long long comb( long long n, long long m, long long p ) {
    if( m > n ) return 0;
    return fac[n] * vfac[m] % p * vfac[n-m] % p;
}
long long lucas( long long n, long long m, long long p ) {
    if( m > n ) return 0;
    if( n / p == 0 ) return 1;//key point!
    return lucas( n / p, m / p, p ) * comb( n % p, m % p, p ) % p;
}
}
long long exgcd( long long a, long long b, long long &x, long long &y ) {
    if( b == 0 ) {
        x = 1;
        y = 0;
        return a;
    } else {
        long long x0, y0;
        long long cd = exgcd( b, a % b, x0, y0 );
        x = y0;
        y = x0 - (a/b) * y0;
        return cd;
    }
}

//    a^(-1)
/* way 1
long long inverse( long long a, long long mod ) {    //    require mod is a prime
    return mpow(a, mod-2, mod);
}
*/
// way 2
long long inverse( long long a, long long mod ) {
    long long x, y;
    exgcd( a, mod, x, y );
    return (x % mod + mod) % mod;
}

//    Chinese Remainder Theorem
//    x = a ( mod m )
long long crt( vector<long long> va, vector<long long> vm ) {
    int n = (int)va.size();
    long long M = 1;
    for( int t = 0; t < n; t++ )
        M *= vm[t];
    long long ans = 0;
    for( int t = 0; t < n; t++ ) {
        long long ci = M / vm[t];
        long long invci = inverse(ci,vm[t]);
        ans = (ans + ci * invci % M * va[t])% M;
    }
    return ans;
}

int main() {
    vector<long long> va, vm;
    va.push_back(2);vm.push_back(3);
    va.push_back(3);vm.push_back(5);
    va.push_back(0);vm.push_back(4);
    long long ans = crt(va, vm);
    printf("%I64d\n", ans);
}

原文地址:https://www.cnblogs.com/EdSheeran/p/8453013.html

时间: 2024-07-30 20:09:57

18寒假的数论的相关文章

牛客网练习赛18 A 【数论/整数划分得到乘积最大/快速乘】

链接:https://www.nowcoder.com/acm/contest/110/A 来源:牛客网 题目描述 这题要你回答T个询问,给你一个正整数S,若有若干个正整数的和为S,则这若干的数的乘积最大是多少?请输出答案除以2000000000000000003(共有17 个零) 的余数. 举例来说,当 S = 5 时,若干个数的和为 5 的情形有以下 7 种(不考虑数字的顺序的话): 1 + 1 + 1 + 1 + 1 1 + 1 + 1 + 2 1 + 1 + 3 1 + 2 + 2 1

18寒假第一测

猪猪的想法输入文件:thought.in输出文件:thought.out时间限制:1 second空间限制:128 MB题目描述狗蛋养了许多只可爱的猪猪,这些猪猪她萌都有一些奇怪的想法:比如说猪猪喜欢猪猪,猪猪之间的喜欢是一个很有趣的事情--喜欢是可以传递的,例如猪猪喜欢猪猪,猪猪喜欢猪猪,那么可以说猪猪喜欢猪猪.有意思的一点是,她萌不喜欢自恋的猪猪,一旦出现了自恋的猪猪,那么极有可能的是这个团体出现危险.现在给你只猪猪对单方面的关系,请问这个只猪猪组成的团体是否危险呢?是输出Yes ,否输出N

18寒假第三测

第一题:找LCA,两点之间的距离=他们各自到起点的距离 - 2*LCA到起点的距离 #include<bits/stdc++.h> using namespace std; const int maxn = 100015, P = 20; int head[2 * maxn],to[2 * maxn],last[2 *maxn],co[2 * maxn],dep[maxn], idx, anc[maxn][P+1],dis[maxn]; void dfs(int u,int from){ //

18寒假第二测

第一题:二维树状数组,bit[x][y]表示从(1,1)到(x,y)的和,二维的坐标从一维的推过来,正确性可以用一个递增和一个递减的序列单调性证明,至于构图就当黑箱吧 #include <cstdio> int n, m, q; struct Case1 { int bit[100010]; void modify( int p, int d ) { for( int i = p; i <= m; i += i & -i ) bit[i] += d; } int query( i

18寒假第六测

第一题:乘法修改的线段树 一定不能将change,modify分类讨论定两个标记,会有顺序影响 lazy标记一定要long long,又忘了... 代码和上一次差不多 第二题:离散暴力,也可以扫描线 离散时要将格子映射成点,不然会出现以下情况: 算横着的小矩形宽就是2,算黄色面积宽还是2,因为没有2让3去减 如果映射成点,就像这样,,放图比较好理解,就像扫描线,一个叶子节点存的是一个左闭右开的区间 也可以离散+扫描线,但还没写出来 #include <bits/stdc++.h> using

18寒假第五测

第一题 线段树 树状数组存差b[i] = a[i]-a[i-1],反正是单点查询,我为什么没想到...很傻的用线段树 #include<bits/stdc++.h> using namespace std; #define maxn 100005 #define ll long long int n, m, a[maxn]; struct SegmentTree{ struct node{ ll sum; int lazy; }; node Tree[maxn << 2]; #de

18寒假13测

题目名称 buy slide divide 输入 buy.in slide.in divide.in 输出 buy.out slide.out divide.out 每个测试点时限 1秒 1秒 1秒 内存限制 256MB 256MB 256MB 测试点数目 10 10 10 每个测试点分值 10 10 10 是否有部分分 无 无 无 题目类型 传统 传统 传统 buy description: 地主zxr想买一些长方形的土地,所有的土地可以分为若干组,每一组的土地的价格为这一组里的最长的长乘上最

18寒假12测

Day1 题目名称 party array treasure 输入 party.in array.in treasure.in 输出 party.out array.out treasure.out 每个测试点时限 1秒 1秒 1秒 内存限制 64MB 64MB 64MB 测试点数目 10 10 10 每个测试点分值 10 10 10 是否有部分分 无 无 无 题目类型 传统 传统 传统 party 题目描述: 在M公司里,每个人只有一个直属上司(除了boss).这个公司举办派对,每个人可以给派

Gym -102007 :Benelux Algorithm Programming Contest (BAPC 18) (寒假自训第5场)

A .A Prize No One Can Win 题意:给定N,S,你要从N个数中选最多是数,使得任意两个之和不大于S. 思路:排序,然后贪心的选即可. #include<bits/stdc++.h> #define ll long long #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=2000010; ll a[maxn]; int main() { int N,ans; l