zoukankan      html  css  js  c++  java
  • 数论·杂

    欧几里得(辗转相除)

    int gcd(int a, int b) {
    	return b == 0 ? a : gcd(b, a % b);
    } //递归版
    
    int gcd(int a, int b) {
    	if(a < b) swap(a, b);
    	int c; 
    	while(b) c = a % b, a = b, b = c;
    	return a;
    } //循环版
    

    扩展欧几里得

    int exgcd(int a, int b, int &x, int &y) {
        if(b == 0) { x = 1, y = 0, return a; }
        int ans = exgcd(b, a % b, x, y);
        int oo = x;
        x = y, y = oo - a / b * y;
        return ans; //a和b的最大公因数
    }
    

    逆元

    //扩展欧几里得求逆元
    int ny(int a, int m) {
        int x, y;
        int gcd = exgcd(a, m, x, y);
        if(1 % gcd != 0) return -1;
        x *= 1 / gcd;
        m = abs(m);
        int ans = x % m;
        if(ans <= 0) ans += m;
        return ans;
    }
    
    //费马小定理求逆元
    ll ksm(ll a, ll b, ll p) {
        ll res = 1;
        while(b) {
            if(b & 1) res = res * a % p;
            a = a * a % p;
            b >> 1;
        }
        return res;
    }
    
    ll fm(ll a, ll p) { return ksm(a, p - 2, p); }
    
    //线性递推求逆元
    int inv[N];
    void ny(int p) {
        inv[1] = 1;
        for(int i = 2; i < p; i ++)
            inv[i] = (p - p / i) * inv[p % i] % p;
    }
    
    //欧拉定理求逆元
    int phi(int x) {
        int ans = x;
        for(int i = 2; i * i <= x; 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;
    }
    

    中国剩余定理

    #include<cstdio>
    #define ll long long
    ll n, a[16], m[16], M, mul = 1, res;
    
    void exgcd(ll a, ll b, ll &x, ll &y) {
        if(b == 0) { x = 1; y = 0; return; }
        exgcd(b, a % b, x, y);
        int z = x; x = y, y = z - y * (a / b);
    }
    int main() {
        cin >> n;
        for(int i = 1; i <= n; i ++) {
            cin >> m[i] >> a[i];
            mul *= m[i];
        } 
        for(int i = 1; i <= n; i ++) {
            M = mul / m[i];
            ll x = 0, y = 0;
            exgcd(M, m[i], x, y);
            res += a[i] * M * (x < 0 ? x + m[i] : x);
        }
        cout << res % mul;
        return 0;
    }
    

    组合数打表

    #include <iostream>
    #define LL long long;
    using namespace std;      
    const LL mod = 1e9+7;     //大质数P
    const LL N = 1e6+5;       //n的范围
    LL fac[N], inv[N];	  //阶乘数组 阶乘逆元
    
    LL power(LL a, int b) {
    	LL res = 1;
    	while(b) {
    		if(b & 1) res = res * a % mod;
    		a = a * a % mod;
    		b >>= 1;
    	}
    	return res;
    }
    void Init()	{	//这里给阶乘及逆元打表,以备让你求多次组合数
    	fac[0] = 1;     
    	for(int i = 1; i < N; i++)
    		fac[i] = fac[i - 1] * i % mod;
    	inv[N - 1] = power(fac[N - 1], mod - 2);
    	for(int i = N - 2; i >= 0; i ++) inv[i] = inv[i+1] * (i+1) % mod;
    } 
    int main() {
    	int m, n;
    	cin >> m >> n;
    	LL res = fac[n] * inv[m] % mod *inv[n-m] % mod;
    	cout << res;
    	return 0;
    }
    

    一些题

    P2303 [SDOI2012] Longge 的问题

    简化题意:给定n,求 (displaystylesum^n_{i=1}gcd(i,n))

    数据范围(1le nle2^{32})

    解题思路

    [displaystylesum^n_{i=1}gcd(i,n)\=sum_{j=1}^n(j*sum^n_{i=1}[gcd(i,n)=j])\=sum^n_{j=1}(j*sum^n_{i=1}[gcd(i/j,n/j)=1](j|i,j|n))\ ]

    #include<cstdio>
    using namespace std;
    typedef long long ll;
    
    ll n;
    ll fi() {
    	ll ans = n;
    	for(ll i = 2; i * i <= n; i ++)
    	  if(n % i == 0) {
    	  	int b = 0;
    	  	while(n % i == 0) b ++, n /= i;
    		ans /= i;
    		ans *= b * i - b + i;
    	}
    	if(n > 1) ans /= n, ans *= n + n - 1;
    	return ans;
    }
    
    int main() {
    	scanf("%lld", &n);
    	printf("%lld", fi());
    	return 0;
    }
    

    P2155 [SDOI2008]沙拉公主的困惑

    简化题意:给定T,R,T组数据,R为质数,每组给定N,M,求1~N!中与M!互质的数的个数,结果对R取模

    数据范围(1le Mle Nle10~000~000,1le Tle10~000,2le Rle1000~000~000+10)

    解题思路

    [ans=frac{n!}{m!}varphi(m!)\=frac{n!}{m!}m!prod_{p|m}(1-frac1p)\=n!prod_{p|m}(1-frac1p)\=n!frac{prod(p-1)}{prod p} ]

    其中 (ple M)(p) 为质数

    然后处理 (n!)(prod(p-1))(prod p)(R) 的逆元

    考虑到 (n!) 中的因子 (R) 可能和 (prod p) 中的 (R) 约掉,所以对 (n ge R)(n!) 消去一个 (R),对 (M ge R)(prod p) 同时消去一个 (R)

    #include <bits/stdc++.h>
    #define N 10000000
    using namespace std;
    
    bool tag[N + 1];
    int T, R, n, m, cnt;
    int pri[N], inv[N + 1], pi[N], p[N], nn[N + 1], pos[N + 1];
    
    void Euler() {
    	for(int i = 2; i <= N; i ++) {
    		if(!tag[i]) pri[++ cnt] = i;
    		for(int j = 1; j <= cnt and pri[j] * i <= N; j ++) {
    			tag[pri[j] * i] = 1;
    			if(i % pri[j] == 0) break;
    		}
    	}
    }
    
    void work() {
    	inv[1] = pi[0] = p[0] = nn[0] = 1;
    	for(int i = 2; i < R and i <= N; i ++) //线性求逆元 
    		inv[i] = 1ll * (R - R / i) * inv[R % i] % R;
    		
    	for(int i = 1; i <= cnt; i ++) // $prod(p - 1)$ 
    		pi[i] = 1ll * pi[i - 1] * (pri[i] - 1) % R;
    	
    	for(int i = 1; i <= cnt; i ++) // $prod p$
    		if(pri[i] != R) p[i] = 1ll * p[i - 1] * inv[pri[i] % R] % R;
    		else p[i] = p[i - 1];
    	
    	for(int i = 1; i <= N; i ++) // n!
    		if(i != R) nn[i] = 1ll * nn[i - 1] * i % R;
    		else nn[i] = nn[i - 1];  
    	
    	for(int i = 2; i <= N; i ++) //位置 
    		if(tag[i]) pos[i] = pos[i - 1];
    		else pos[i] = pos[i - 1] + 1;
    }
    
    int main() {
    	cin >> T >> R;
    	Euler();
    	work();
    	while(T --) {
    		cin >> n >> m;
    		if(n >= R and m < R) cout << 0 << "
    ";
    		else cout << 1ll * nn[n] * pi[pos[m]] % R * p[pos[m]] % R << "
    ";
    	}
    	return 0;
    }			
    

    P4345 [SHOI2015]超能粒子炮·改

    简化题意:t组数据,每组给定n,k,求 (displaystylesum_{i=0}^kC^i_n\%2333)

    数据范围(1le tle100~000;n,kle 10^{18})

    解题思路:用到了卢卡斯定理

    [C^m_n\%p=C^{m/p}_{n/p}*C^{m\%p}_{n\%p}\%p ]

    [f(n,k)=sum^k_{i=0}C^i_n\=sum^k_{i=0}C^{i/p}_{n/p}*C^{i\%p}_{n\%p}\%p\=sum^{p-1}_{i=0}C^i_{n\%p}*(C^0_{n/p}+C^1_{n/p}+dots+C^{k/p-1_{n/p}})\=f(n\%p,p-1)*f(n/p,k/p-1) ]

    分块处理

    #include<bits/stdc++.h>
    #define N 2333
    using namespace std;
    typedef long long ll;
    ll n, k, t, c[N + 5][N + 5], f[N + 5][N + 4];
    
    ll lucas(ll x, ll y) {
    	if(x < y) return 0; 
    	if(x < N and y < N) return c[x][y];
    	return lucas(x / N, y / N) * c[x % N][y % N] % N;
    }
    
    ll ovo(ll n, ll k) {
    	if(k < 0) return 0;
    	if(!n or !k) return 1;
    	if(n < N and k < N) return f[n][k];
    	return (ovo(n / N, k / N - 1) * f[n % N][N - 1] + lucas(n / N, k / N) * f[n % N][k % N]) % N;
    }
     
    int main() {
    	cin >> t;
    	c[0][0] = 1;
    	for(int i = 1; i <= N + 2; i ++) c[i][i] = c[i][0] = 1;
    	for(int i = 1; i <= N + 2; i ++) 
    	  for(int j = 1; j < i; j ++)
    	    c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % N;
    	    
    	f[0][0] = 1;
    	for(int i = 1; i <= N + 2; i ++) f[i][0] = 1;
    	for(int i = 0; i <= N + 2; i ++) 
    	  for(int j = 1; j <= N + 2; j ++)
    	  	f[i][j] = (c[i][j] + f[i][j - 1]) % N;
    	  	
    	while(t --) {
    		cin >> n >> k;
    	 	cout << ovo(n, k) << "
    ";
    	}
    	return 0;
    }
    
    而我们终其一生,都希望能成为更好的人。
  • 相关阅读:
    java.lang.NoClassDefFoundError: org.junit.runner.Runner
    SpringMVC 八大注解
    spring @autowired使用总结
    Git使用入门
    N21_栈的压入弹出序列。
    N20_包含min函数的栈
    N19_顺时针打印指针
    N17_判断树B是不是树A的子结构
    N16_合并两个排序链表
    N15_反转链表后,输出新链表的表头。
  • 原文地址:https://www.cnblogs.com/moziii/p/13574025.html
Copyright © 2011-2022 走看看