分类: 数论

  • 洛谷3327 约数个数和 复习

    众所周知,这题不是个人也会。

    $$ \text{首先可知}d\left( nm \right) =\sum_{a|n}{\sum_{b|m}{\left[ \mathrm{gcd}\left( a,b \right) =1 \right]}} \\ \sum_{1\le i\le n}{\sum_{1\le j\le m}{\sum_{a|i}{\sum_{b|j}{\left[ \mathrm{gcd}\left( a,b \right) =1 \right]}}}} \\ =\sum_{1\le i\le n}{\sum_{1\le j\le m}{\sum_{a|i}{\sum_{b|j}{\sum_{k|gcd\left( a,b \right)}{\mu \left( k \right)}}}}} \\ =\sum_{1\le k\le n}{\mu \left( k \right) \sum_{1\le i\le n}{\sum_{1\le j\le m}{\sum_{a|i}{\sum_{b|j}{\left[ k|\mathrm{gcd}\left( a,b \right) \right]}}}}} \\ =\sum_{1\le k\le n}{\mu \left( k \right) \sum_{1\le a\le n}{\sum_{1\le b\le m}{\sum_{a|i,i\le n}{\sum_{b|j,j\le m}{\left[ k|gcd\left( a,b \right) \right]}}}}} \\ a\gets ak,b\gets bk \\ =\sum_{1\le k\le n}{\mu \left( k \right) \sum_{1\le ak\le n}{\sum_{1\le bk\le m}{\left[ k|gcd\left( ak,bk \right) \right] \lfloor \frac{n}{ak} \rfloor \lfloor \frac{m}{bk} \rfloor}}} \\ =\sum_{1\le k\le n}{\mu \left( k \right) \sum_{1\le a\le \lfloor \frac{n}{k} \rfloor}{\sum_{1\le b\le \lfloor \frac{m}{k} \rfloor}{\lfloor \frac{n}{ak} \rfloor \lfloor \frac{m}{bk} \rfloor}}} \\ =\sum_{1\le k\le n}{\mu \left( k \right) \sum_{1\le a\le \lfloor \frac{n}{k} \rfloor}{\sum_{1\le b\le \lfloor \frac{m}{k} \rfloor}{\lfloor \frac{\lfloor \frac{n}{k} \rfloor}{a} \rfloor \lfloor \frac{\lfloor \frac{m}{k} \rfloor}{b} \rfloor}}} \\ =\sum_{1\le k\le n}{\mu \left( k \right) \left( \sum_{1\le a\le \lfloor \frac{n}{k} \rfloor}{\lfloor \frac{\lfloor \frac{n}{k} \rfloor}{a} \rfloor} \right) \left( \sum_{1\le b\le \lfloor \frac{m}{k} \rfloor}{\lfloor \frac{\lfloor \frac{m}{k} \rfloor}{b} \rfloor} \right)} \\ S\left( n \right) =\sum_{1\le i\le n}{\lfloor \frac{n}{i} \rfloor} \\ \text{原式}=\sum_{1\le k\le n}{\mu \left( k \right) S\left( \lfloor \frac{n}{k} \rfloor \right) S\left( \lfloor \frac{m}{k} \rfloor \right)} \\ $$

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using int_t = long long int;
    
    const int_t LARGE = 5e4;
    
    using std::cin;
    using std::cout;
    using std::endl;
    
    int_t S[LARGE + 1];
    bool isPrime[LARGE + 1];
    int_t factor[LARGE + 1];
    int_t mu[LARGE + 1];
    int_t muSum[LARGE + 1];
    
    int_t Sx(int_t n) {
        int_t result = 0;
        int_t i = 1;
        while (i <= n) {
            int_t next = n / (n / i);
            result += (next - i + 1) * (n / i);
            i = next + 1;
        }
        return result;
    }
    
    int_t query(int_t n, int_t m) {
        if (n > m)
            std::swap(n, m);
        int_t result = 0;
        int_t i = 1;
        while (i <= n) {
            int_t next = std::min(n / (n / i), m / (m / i));
            result += (muSum[next] - muSum[i - 1]) * S[n / i] * S[m / i];
            i = next + 1;
        }
        return result;
    }
    
    int main() {
        for (int_t i = 1; i <= LARGE; i++) {
            S[i] = Sx(i);
        }
        memset(isPrime, 1, sizeof(isPrime));
        for (int_t i = 2; i <= LARGE; i++) {
            if (isPrime[i]) {
                factor[i] = i;
                for (int_t j = i * i; j <= LARGE; j += i) {
                    isPrime[j] = false;
                    if (!factor[j])
                        factor[j] = i;
                }
            }
        }
        mu[1] = muSum[1] = 1;
        for (int_t i = 2; i <= LARGE; i++) {
            int_t factor = ::factor[i];
            if (i / factor % factor == 0)
                mu[i] = 0;
            else
                mu[i] = mu[i / factor] * -1;
            muSum[i] = muSum[i - 1] + mu[i];
        }
        int T;
        scanf("%d", &T);
        while (T--) {
            int n, m;
            scanf("%d%d", &n, &m);
            auto result = query(n, m);
            printf("%lld\n", result);
        }
        return 0;
    }

     

  • 洛谷2257 YY的GCD 复习

    众所周知,这题是个人就会。

    $$ \text{钦定}N\le M \\ \sum_{1\le i\le N}{\sum_{1\le j\le M}{\left[ \mathrm{gcd}\left( i,j \right) =p \right]}} \\ \sum_p{\sum_{1\le pi\le N}{\sum_{1\le pj\le M}{\left[ \mathrm{gcd}\left( pi,pj \right) =p \right]}}} \\ \sum_p{\sum_{1\le i\le \lfloor \frac{N}{p} \rfloor}{\sum_{1\le j\le \lfloor \frac{M}{p} \rfloor}{\left[ \mathrm{gcd}\left( i,j \right) =1 \right]}}} \\ \sum_p{\sum_{1\le i\le \lfloor \frac{N}{p} \rfloor}{\sum_{1\le j\le \lfloor \frac{M}{p} \rfloor}{\sum_{k|gcd\left( i,j \right)}{\mu \left( k \right)}}}} \\ \sum_p{\sum_{1\le k\le \lfloor \frac{N}{p} \rfloor}{\sum_{1\le ik\le \lfloor \frac{N}{p} \rfloor}{\sum_{1\le jk\le \lfloor \frac{M}{p} \rfloor}{\sum_{k|gcd\left( ik,jk \right)}{\mu \left( k \right)}}}}} \\ \sum_p{\sum_{1\le k\le \lfloor \frac{N}{p} \rfloor}{\sum_{1\le i\le \lfloor \frac{N}{kp} \rfloor}{\sum_{1\le j\le \lfloor \frac{M}{kp} \rfloor}{\mu \left( k \right)}}}} \\ \sum_{1\le p\le N,p\,\,is\,\,prime}{\sum_{1\le k\le \lfloor \frac{N}{p} \rfloor}{\mu \left( k \right) \lfloor \frac{N}{kp} \rfloor \lfloor \frac{M}{kp} \rfloor}} \\ T=kp \\ T\le N \\ \sum_{1\le T\le N}{\sum_{p|T\left( T\text{的所有质因数} \right)}{\lfloor \frac{N}{T} \rfloor \lfloor \frac{M}{T} \rfloor \mu \left( \frac{T}{p} \right)}} \\ =\sum_{1\le T\le N}{\lfloor \frac{N}{T} \rfloor \lfloor \frac{M}{T} \rfloor \sum_{p|T,\left( T\text{的所有质因数} \right)}{\mu \left( \frac{T}{p} \right)}} $$
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <vector>
    using int_t = long long int;
    using std::cin;
    using std::cout;
    using std::endl;
    
    const int_t LARGE = 2e7;
    
    int f[LARGE + 1];
    int fSum[LARGE + 1];
    int mu[LARGE + 1];
    int factor[LARGE + 1];
    bool isPrime[LARGE + 1];
    
    std::vector<int> primes;
    
    int_t query(int_t n, int_t m) {
        if (n > m)
            std::swap(n, m);
    #ifdef DEBUG
        cout << "process " << n << " " << m << endl;
    #endif
        int_t i = 1;
        int_t result = 0;
        while (i <= n) {
            int_t next = std::min(n / (n / i), m / (m / i));
            result += (n / i) * (m / i) * (fSum[next] - fSum[i - 1]);
            i = next + 1;
        }
        return result;
    }
    
    int main() {
        std::ios::sync_with_stdio(false);
        memset(isPrime, 1, sizeof(isPrime));
        isPrime[1] = false;
        for (int_t i = 2; i <= LARGE; i++) {
            if (isPrime[i]) {
                primes.push_back(i);
                for (int_t j = i * i; j <= LARGE; j += i) {
                    isPrime[j] = false;
                    if (factor[j] == 0)
                        factor[j] = i;
                }
                factor[i] = i;
            }
        }
        mu[1] = 1;
        for (int_t i = 2; i <= LARGE; i++) {
            int_t factor = ::factor[i];
            if (i / factor % factor == 0) {
                mu[i] = 0;
            } else {
                mu[i] = mu[i / factor] * -1;
            }
        }
        for (auto prime : primes) {
            for (int_t j = 1; j * prime <= LARGE; j++) {
                f[j * prime] += mu[j];
            }
        }
    #ifdef DEBUG
        for (int_t i = 2; i <= 100; i++) {
            cout << i << ": factor=" << factor[i] << " isPrime=" << isPrime[i]
                 << " mu=" << mu[i] << " f=" << f[i] << endl;
        }
    
    #endif
        for (int_t i = 2; i <= LARGE; i++)
            fSum[i] = fSum[i - 1] + f[i];
        int T;
        scanf("%d", &T);
        while (T--) {
            int n, m;
            scanf("%d%d", &n, &m);
            int_t result = query(n, m);
            printf("%lld\n", result);
        }
        return 0;
    }<span id="mce_marker" data-mce-type="bookmark" data-mce-fragment="1">​</span>

     

  • 洛谷T2062 随机数生成器

    $$ \text{题意:} \\ \text{求}f\left( n \right) =1+\frac{1}{n}\sum_{1\le i\le n}{f\left( i \right)} \\ \text{设}F\left( n \right) =\sum_{1\le i\le n}{f\left( i \right)} \\ f\left( n \right) =1+\frac{1}{n}F\left( n \right) \\ nf\left( n \right) =n+F\left( n \right) \\ \left( n-1 \right) f\left( n-1 \right) =n-1+F\left( n-1 \right) \\ \text{相减} \\ nf\left( n \right) -\left( n-1 \right) f\left( n-1 \right) =n-\left( n-1 \right) +F\left( n \right) -F\left( n-1 \right) \\ nf\left( n \right) -nf\left( n-1 \right) +f\left( n-1 \right) =1+f\left( n \right) \\ \left( 1-n \right) f\left( n-1 \right) =1+\left( 1-n \right) f\left( n \right) \\ f\left( n \right) +\frac{1}{1-n}=f\left( n-1 \right) \\ f\left( n \right) =\frac{1}{n-1}+f\left( n-1 \right) \\ \text{规定}f\left( 1 \right) =1 \\ \text{则}f\left( n \right) =1+\sum_{1\le i<n}{\frac{1}{i}} \\ n\text{较小时暴力计算,}n\text{较大时直接近似} \\ $$

    #pragma GCC target("avx,sse,sse2")
    #pragma GCC optimize("Ofast")
    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstdlib>
    #include <vector>
    #include <iomanip>
    #include <cmath>
    typedef long long int int_t;
    typedef long double real_t;
    
    using std::cin;
    using std::endl;
    using std::cout;
    
    const real_t GAMMA = 0.57721566490153286060651209;
    
    int main(){
        real_t f = 1;
        int_t n;
        cin >> n;
        n -= 1;
        if(n == 0){
            f = 0;
        }else if(n <= 5e7){
            for(int_t i = 1;i <= n;i ++){
                f += (real_t) 1 / i;
            }
        }else{
            f += logl(n) + GAMMA;
        }
        std::cout.setf(std::ios::fixed);
        cout << std::setprecision(5) << f << endl;
        
    	return 0;
    }

     

  • 洛谷1445 樱花

    $$ \text{原式可以整理得到} \\ \frac{xy}{x+y}=n! \\ xy=\left( x+y \right) \times n! \\ \text{设}t=x+y,\text{则}y=t-x \\ x\left( t-x \right) =t\times n! \\ xt-x^2=t\times n! \\ t\left( x-n! \right) =x^2 \\ \text{设}k=x-n!,\text{则}x=k+n! \\ t=\frac{x^2}{k}=\frac{\left( k+n! \right) ^2}{k}=\frac{k^2+\left( n! \right) ^2+2\times k\times n!}{k}=k+2\times n!+\frac{\left( n! \right) ^2}{k} \\ \text{即} \\ t=k+2\times n!+\frac{\left( n! \right) ^2}{k} \\ \text{由于}t,k\text{都是整数,所以,根据}k=x-n!,n\text{确定时,每一个}k\text{可以确定一个唯一的}x\text{和}t\text{,进而确定唯一的}\left( x,y \right) \\ \text{所以答案为}\left( n! \right) ^2\text{的约数个数} $$

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstdlib>
    #include <vector>
    #include <map>
    typedef long long int int_t;
    using std::cin;
    using std::endl;
    using std::cout;
    
    const int_t LARGE = 1000000;
    const int_t mod = 1e9 + 7;
    int_t factor[LARGE + 1];
    bool isPrime[LARGE + 1];
    int_t times[LARGE + 1];
    int main(){
        std::fill(isPrime + 2,isPrime + 1 + LARGE ,true);
        for(int_t i = 2;i <= LARGE ;i ++){
            if(isPrime[i]){
                for(int_t j = i * i;j <= LARGE ;j += i){
                    isPrime[j] = false;
                    factor[j] = i;
                }
                factor[i] = i;
            }
        }
        int_t n;
        cin >> n;
        for(int_t i = 2;i <= n;i++){
            int_t curr = i;
            while(curr != 1){
                int_t fac = factor[curr];
                times[fac] += 1;
                curr /= fac;
            }
        }
        int_t prod = 1;
        for(int_t i = 1;i <= n;i ++){
            prod = prod * (times[i] * 2 + 1) % mod;
        }
        cout << prod << endl;
    	return 0;
    }

     

  • SP7001 VLATTICE

    $$ \text{因为题目中要求}a,b,c\text{都可以取到0,所以我们先考虑}abc\text{都不为0的情况} \\ \sum_{1\le i\le n}{\sum_{1\le j\le n}{\sum_{1\le k\le n}{\left[ gcd\left( i,j,k \right) \ =\ 1 \right]}}} \\ \sum_{1\le i\le n}{\sum_{1\le j\le n}{\sum_{1\le k\le n}{\sum_{d|gcd\left( i,j,k \right)}{\mu \left( d \right)}}}} \\ \sum_{1\le d\le n}{\mu \left( d \right) \sum_{1\le i\le n}{\sum_{1\le j\le n}{\sum_{1\le k\le n}{\sum_{d|gcd\left( i,j,k \right)}{\left[ d|gcd\left( i,j,k \right) \right]}}}}} \\ \sum_{1\le d\le n}{\mu \left( d \right) \sum_{1\le i\le \lfloor \frac{n}{d} \rfloor}{\sum_{1\le j\le \lfloor \frac{n}{d} \rfloor}{\sum_{1\le k\le \lfloor \frac{n}{d} \rfloor}{1}}}} \\ =\sum_{1\le d\le n}{\mu \left( d \right) \lfloor \frac{n}{d} \rfloor ^3} \\ \text{再考虑}abc\text{只有一个为0的情况,这时候等价于二维平面上} \\ 3\sum_{1\le d\le n}{\mu \left( d \right) \lfloor \frac{n}{d} \rfloor ^2} \\ \text{因为}abc\text{一个为0有三种情况,所以需要乘}3 \\ \text{在考虑}abc\text{有两个为0的情况} \\ \text{这时候是一条直线,只有一种可能} \\ \text{所以最后答案为} \\ 3+\sum_{1\le d\le n}{\mu \left( d \right) \lfloor \frac{n}{d} \rfloor ^2\left( \lfloor \frac{n}{d} \rfloor +3 \right)} $$

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <inttypes.h>
    #define debug(x) std::cout << #x << " = " << x << std::endl;
    
    typedef long long int int_t;
    
    using std::cin;
    using std::endl;
    using std::cout;
    
    const int_t LARGE = 1000000;
    int_t factor[LARGE + 1];
    bool isPrime[LARGE + 1];
    int_t mu[LARGE + 1];
    void init() {
    	std::fill(isPrime + 1,isPrime + 1 + LARGE,true);
    	isPrime[1] = false;
    	for(int_t i = 2; i <= LARGE ; i++) {
    		if(isPrime[i]) {
    			for(int_t j = i * i; j <= LARGE ; j += i) {
    				factor[j] = i;
    				isPrime[j] = false;
    			}
    			factor[i] = i;
    			mu[i] = -1;
    		}
    	}
    	mu[1] = 1;
    	for(int_t i = 2; i <= LARGE ; i ++) {
    		if(isPrime[i] == false) {
    			int_t factor = ::factor[i];
    			if((i / factor) % factor == 0) mu[i] = 0;
    			else mu[i] = mu[i / factor] * mu[factor];
    		}
    	}
    	for(int_t i = 2; i <= LARGE ; i ++) {
    		mu[i] += mu[i - 1];
    	}
    }
    
    int main() {
    	init();
    	int T;
    	scanf("%d",&T);
    	for(int_t _i = 1; _i <= T; _i ++) {
    		int_t x;
    		scanf("%lld",&x);
    		int_t result = 3;
    		int_t i = 1;
    		while(i <= x) {
    			int_t next = x / (x / i);
    			int_t c = x / i;
    			result += (mu[next] - mu[i - 1]) * (c * c * (c + 3));
    			i = next + 1;
    		}
    		printf("%lld\n",result);
    	}
    	return 0;
    }

     

  • SDOI2012 Longge的问题

    $$ \sum_{1\le i\le n}{gcd\left( i,n \right)} \\ =\sum_{d|n}{d\sum_{1\le i\le n}{\left[ gcd\left( i,n \right) =d \right]}} \\ =\sum_{d|n}{d\sum_{1\le i\le \frac{n}{d}}{\left[ gcd\left( i,\frac{n}{d} \right) =1 \right]}} \\ =\sum_{d|n}{d\varphi \left( \frac{n}{d} \right)} \\ \text{用杜教筛求}\varphi \left( x \right) \text{即可}. \\ $$

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <inttypes.h>
    #include <map>
    #define debug(x) std::cout << #x << " = " << x << std::endl;
    
    typedef long long int int_t;
    
    using std::cin;
    using std::endl;
    using std::cout;
    
    const int_t LARGE = 1000000;
    int_t phi[LARGE + 1];
    void init(){
    	for(int_t i = 1 ; i <= LARGE ;i++){
    		phi[i] = i;
    	}
    	for(int_t i = 2; i <= LARGE ;i++){
    		if(phi[i] == i){
    			for(int_t j = i;j <= LARGE ;j += i){
    				phi[j] /= i;
    				phi[j] *= (i - 1);
    			}
    		}
    		phi[i] += phi[i - 1];
    	}
    }
    int_t phiPrefix(int_t n){
    	if(n <= LARGE) return phi[n];
    	static std::map<int_t,int_t> memory;
    	if(memory.count(n)) return memory[n];
    	int_t result = n * (n + 1) / 2;
    	int_t i = 2;
    	while(i <= n){
    		int_t next = n / (n / i);
    		result -= phiPrefix(n / i) * (next - i + 1);
    		i = next + 1;
    	}
    	return memory[n] = result;
    	
    }
    
    int main() {
    	init();
    	int_t n;
    	std::vector<int_t> factors;
    	cin >> n;
    	for(int_t i = 1;i * i <= n;i++){
    		if(n % i == 0){
    			factors.push_back(i);
    			if(i * i != n){
    				factors.push_back(n / i);
    			}
    		}
    	}
    //	debug("qwq");
    	int_t result = 0;
    	for(int_t i = 0;i < factors.size();i++){
    		int_t curr = factors[i];
    		result += (phiPrefix(curr) - phiPrefix(curr - 1)) * n / curr;
    	}
    	cout << result << endl;
        return 0;
    }

     

  • luogu2429 制杖题

    $$\text{设}f\left( n,d \right) \text{表示不超过}n\text{的}d\text{的倍数的和}\\f\left( n,d \right) =\sum_{1\le i\le \lfloor \frac{n}{d} \rfloor}{d\times i}=d\times \sum_{1\le i\le \lfloor \frac{n}{d} \rfloor}{i}=d\times \frac{\left( \lfloor \frac{n}{d} \rfloor \right) \left( \left( \lfloor \frac{n}{d} \rfloor \right) +1 \right)}{2}\\\text{对于}n\times m\le 10^7\\\text{标记所有给定质数的倍数,然后统计被标记的数的和即可。}\\\text{对于}n\le \text{20的数据点}\\\text{枚举质数集合的子集,然后容斥即可。}\\\text{或者说是反演。}\\\sum_{S\subseteq given\ primes\ and\ S\ne \varnothing}{\mu \left( \prod_{p\in S}{p} \right) f\left( m,\prod_{p\in S}{p} \right)}\\=\sum_{S\subseteq given\ primes\ and\ S\ne \varnothing}{\left( -1 \right) ^{|S|-1}f\left( m,\prod_{p\in S}{p} \right)}$$

    #include <iostream>
    #include <algorithm>
    #include <vector>
    
    using int_t = long long int;
    
    const int_t mod = 376544743;
    const int_t inv2 = 188272372;
    using std::cin;
    using std::cout;
    using std::endl;
    
    int_t count(int_t x)
    {
        int_t result = 0;
        while (x)
        {
            result += 1;
            x -= (x & -x);
        }
        return result;
    }
    char bits[1 << 22];
    int_t f(int_t n, int_t d)
    {
        return (n / d) * (n / d + 1) % mod * inv2 % mod * d % mod;
    }
    int main()
    {
        std::vector<int_t> primes;
        int_t result = 0;
        int_t n, m;
        cin >> n >> m;
        for (int_t i = 0; i < n; i++)
        {
            int_t p;
            cin >> p;
            primes.push_back(p);
        }
        if (n > 20)
        {
            static bool marks[10000000 + 1];
            for (int_t x : primes)
            {
                for (int_t i = 1; i * x <= m; i++)
                {
                    marks[i * x] = true;
                }
            }
            for (int_t i = 1; i <= m; i++)
            {
                if (marks[i])
                {
                    result = (result + i) % mod;
                }
            }
        }
        else
        {
            for (int_t i = 0; i < (1 << n); i++)
                bits[i] = count(i);
    
            for (int_t i = 1; i < (1 << n); i++)
            {
                int_t bits = ::bits[i];
                int_t prod = 1;
                bool flag = true;
                for (int_t j = 0; j < n; j++)
                {
                    if (i & (1 << j))
                    {
                        prod *= primes[j];
                    }
                    if (prod > m)
                    {
                        flag = false;
                        break;
                    }
                }
                if (flag == false)
                    continue;
                if (bits % 2)
                {
                    result = (result + f(m, prod)) % mod;
                }
                else
                {
                    result = (result - f(m, prod) + mod) % mod;
                }
            }
        }
        cout << result << endl;
        return 0;
    }

     

  • luogu1306 斐波那契公约数

    $$ \text{设斐波那契数列的第}n\text{项的值为}a\text{,第}n+\text{1项的值为}b \\ \text{则}f\left( n+1 \right) =b,f\left( n+2 \right) =a+b,f\left( n+3 \right) =a+2b \\ f\left( m \right) =f\left( m-n-1 \right) a+f\left( m-n \right) b \\ gcd\left( f\left( n \right) ,f\left( m \right) \right) =gcd\left( f\left( n \right) ,f\left( m \right) \%f\left( n \right) \right) =gcd\left( a,f\left( m-n \right) b \right) \\ a,b\text{互质,所以} \\ gcd\left( f\left( n \right) ,f\left( m \right) \right) =gcd\left( f\left( n \right) ,f\left( m-n \right) \right) \\ \text{可以递归证明} \\ gcd\left( f\left( n \right) ,f\left( m \right) \right) =gcd\left( f\left( n \right) ,f\left( m\%n \right) \right) =gcd\left( f\left( gcd\left( n,m \right) \right) ,f\left( 0 \right) \right) =f\left( gcd\left( n,m \right) \right) $$

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <string>
    using std::cin;
    using std::cout;
    using std::endl;
    
    using int_t = long long int;
    
    const int_t mod = 1e8;
    
    struct Matrix
    {
        int_t data[21][21];
        int_t n;
        Matrix(int_t n)
        {
            this->n = n;
            memset(data, 0, sizeof(data));
        }
        int_t &operator()(int_t r, int_t c)
        {
            return data[r][c];
        }
        int_t *operator[](int_t row)
        {
            return data[row];
        }
        Matrix operator*(Matrix another)
        {
            Matrix result(n);
            for (int_t i = 1; i <= n; i++)
            {
                for (int_t j = 1; j <= n; j++)
                {
                    for (int_t k = 1; k <= n; k++)
                    {
                        result[i][j] = (result[i][j] + (*this)[i][k] * another[k][j] % mod) % mod;
                    }
                }
            }
            return result;
        }
        Matrix operator^(int_t index)
        {
            Matrix base = *this;
            Matrix result(n);
            for (int_t i = 1; i <= n; i++)
                result[i][i] = 1;
            while (index)
            {
                if (index & 1)
                    result = result * base;
                base = base * base;
                index >>= 1;
            }
            return result;
        }
    };
    int_t gcd(int_t a, int_t b)
    {
        if (b == 0)
            return a;
        return gcd(b, a % b);
    }
    int main()
    {
        int_t a, b;
        cin >> a >> b;
        int_t n = gcd(a, b);
    
        Matrix init(2);
        init(1, 2) = 1;
        Matrix trans(2);
        trans(2, 2) = 1;
        trans(1, 2) = 1;
        trans(2, 1) = 1;
        char buff[20];
        sprintf(buff, "%lld", (init * (trans ^ n))[1][1]);
        std::string str = buff;
        // while (str.length() < 8)
        //     str = '0' + str;
        cout << str << endl;
    
        return 0;
    }

     

  • NOI2018 屠龙勇士

    $$ \text{首先考虑}a_i\le p_i\text{的情况} \\ \text{假设攻击第}i\text{条龙时的攻击为}A_i \\ \text{那么对于第}i\text{条龙,就是求一个}x\text{,满足} \\ x\times A_i-yp_i=a_i \\ \text{即}A_ix=a_i\ \left( mod\ p_i \right) \\ \text{因为}a_i\le \text{p}_i\text{,所以不会出现攻击次数为负的情况。} \\ \text{所以题目要求等价于解方程组} \\ \begin{cases} A_1x\equiv a_1\ \ \left( mod\ p_1 \right)\\ A_2x\equiv a_2\ \ \left( mod\ p_2 \right)\\ …\\ A_nx\equiv a_n\ \ \left( mod\ p_n \right)\\ \end{cases} \\ \text{然而}exCRT\text{只能处理}A_i=\text{1的情况}.. \\ \text{所以需要转变一下} \\ \text{拿出来第}i\text{个方程} \\ A_ix+p_iy=a_i \\ \text{我们现在要求一个}x. \\ \text{我们可以先求出这个方程的一组解}\left( x_{i}^{‘},y_{i}^{‘} \right) \\ \text{那么则有}x\equiv x_{i}^{‘}\left( mod\ \frac{p_i}{gcd\left( A_i,p_i \right)} \right) \\ \text{所以原方程组变为} \\ \begin{cases} x\equiv x_{1}^{‘}\left( mod\ \frac{p_1}{gcd\left( A_1,p_1 \right)} \right)\\ x\equiv x_{1}^{‘}\left( mod\ \frac{p_2}{gcd\left( A_2,p_2 \right)} \right)\\ …\\ x\equiv x_{n}^{‘}\left( mod\ \frac{p_n}{gcd\left( A_n,p_n \right)} \right)\\ \end{cases} \\ \text{这个方程组可以使用}exCRT\text{求解。} \\ \text{考虑一下}a_i>p_i\text{的情况。} \\ \text{这个时候满足}p_i=1 \\ \text{那么我们只需要求出把每条龙血砍到非正的次数,取个最大值即可。} \\ $$

    #include <iostream>
    #include <algorithm>
    #include <set>
    #include <utility>
    #include <assert.h>
    #include <functional>
    using int_t = long long int;
    using pair_t = std::pair<int_t, int_t>;
    using std::cin;
    using std::cout;
    using std::endl;
    
    const int_t LARGE = 100000;
    
    pair_t exgcd(int_t a, int_t b)
    {
        if (b == 0)
            return pair_t(1, 0);
        auto temp = exgcd(b, a % b);
        int_t x = temp.first;
        int_t y = temp.second;
        return pair_t(y, x - a / b * y);
    }
    
    int_t gcd(int_t a, int_t b)
    {
        if (b == 0)
            return a;
        return gcd(b, a % b);
    }
    //求x模p意义下的逆元
    int_t inv(int_t x, int_t p)
    {
        x = (x % p + p) % p;
        if (gcd(x, p) != 1)
            return -1;
        int_t inv = exgcd(x, p).first;
        inv = (inv % p + p) % p;
        return inv;
    }
    int_t mul(int_t a, int_t b, int_t p)
    {
        int_t result = 0;
        while (b)
        {
            if (b & 1)
            {
                result = (result + a) % p;
            }
            a = (a + a) % p;
            b >>= 1;
        }
        return result;
    }
    //求方程Ax+By=C的最小非负解
    int_t solve(int_t A, int_t B, int_t C)
    {
        int_t gcd = ::gcd(A, B);
        if (C % gcd)
            return -1;
        auto temp = exgcd(A, B);
        int_t x = temp.first;
        x = mul(x, C / gcd, B / gcd);
        x = (x % (B / gcd) + B / gcd) % (B / gcd);
        return x;
    }
    struct Processor
    {
        int_t n, m;
        //系数
        int_t a[LARGE + 1];
        //模数
        int_t rec[LARGE + 1];
        int_t reward[LARGE + 1];
        //攻击
        int_t attack[LARGE + 1];
        //模数
        int_t mod[LARGE + 1];
        //系数
        int_t c[LARGE + 1];
        // int_t attacks[LARGE + 1];
        std::multiset<int_t, std::greater<int_t>> swords;
        int_t process()
        {
            cin >> n >> m;
            for (int_t i = 1; i <= n; i++)
            {
                cin >> a[i];
            }
            bool flag = false;
            for (int_t i = 1; i <= n; i++)
            {
                cin >> rec[i];
                if (rec[i] != 1)
                    flag = true;
            }
            for (int_t i = 1; i <= n; i++)
            {
                cin >> reward[i];
            }
            for (int_t i = 1; i <= m; i++)
            {
                int_t x;
                cin >> x;
                swords.insert(x);
            }
            for (int_t i = 1; i <= n; i++)
            {
                int_t attack = next(a[i]);
                this->attack[i] = attack;
                // cout << "x=" << a[i] << "(mod " << mod[i] << ")" << endl;
                swords.insert(reward[i]);
            }
            if (flag == false)
            {
                int_t result = 0;
                for (int_t i = 1; i <= n; i++)
                {
                    result = std::max(result, a[i] / attack[i] + (a[i] % attack[i] != 0));
                }
                return result;
            }
            else
            {
                for (int_t i = 1; i <= n; i++)
                {
                    mod[i] = rec[i] / gcd(rec[i], attack[i]);
                    c[i] = solve(attack[i], rec[i], a[i]);
                    if (c[i] == -1)
                        return -1;
                    // cout << c[i] << " " << mod[i] << endl;
                }
                int_t M = mod[1];
                int_t prex = c[1];
                for (int_t i = 2; i <= n; i++)
                {
                    int_t A = M;
                    int_t B = mod[i];
                    int_t C = ((c[i] - prex) % B + B) % B;
                    int_t gcd = ::gcd(A, B);
                    int_t x = exgcd(A, B).first;
                    if (C % gcd)
                        return -1;
                    x = mul(x, C / gcd, B / gcd);
                    x = (x % (B / gcd) + (B / gcd)) % (B / gcd);
                    int_t preM = M;
                    M = M / gcd * mod[i];
                    prex = (mul(x, preM, M) + prex) % M;
                }
                return prex;
            }
        }
        int_t next(int_t val)
        {
            decltype(swords.begin()) ptr;
            if (val < *(--swords.end()))
            {
                ptr = (--swords.end());
            }
            else
            {
                ptr = swords.lower_bound(val);
                while (*ptr > val)
                {
                    ptr++;
                }
            }
            int_t temp = *ptr;
            swords.erase(ptr);
            return temp;
        }
    };
    
    int main()
    {
    #ifdef ONLINE_JUDGE
        freopen("dragon.in", "r", stdin);
        freopen("dragon.out", "w", stdout);
    #endif
        int_t T;
        cin >> T;
        for (int_t i = 1; i <= T; i++)
        {
            Processor *p = new Processor;
            cout << p->process() << endl;
            delete p;
        }
        return 0;
    }

     

  • TJOI2016 求和

    $$ \text{题意:} \\ \text{求}f\left( n \right) =\sum_{0\le i\le n}{\sum_{0\le j\le i}{S_2\left( i,j \right) \times 2^j\times j!}} \\ \text{第二类斯特林数的通项公式:} \\ S\left( i,j \right) =\frac{1}{j!}\sum_{0\le k\le j}{\left( \begin{array}{c} j\\ k\\ \end{array} \right) \left( -1 \right) ^{j-k}k^i} \\ \text{代入,因为}j>i\text{时,}S_2\left( i,j \right) \text{为0,所以求和上界可以放到}n \\ f\left( n \right) =\sum_{0\le j\le n}{2^j\times j!\sum_{0\le i\le n}{S\left( i,j \right)}} \\ f\left( n \right) =\sum_{0\le j\le n}{2^j\sum_{0\le i\le n}{\sum_{0\le k\le j}{\left( \begin{array}{c} j\\ k\\ \end{array} \right) \times \left( -1 \right) ^{j-k}k^i}}} \\ \text{整理一下} \\ f\left( n \right) =\sum_{0\le j\le n}{j!\sum_{0\le k\le j}{\frac{2^j}{k!\left( j-k \right) !}\times \left( -1 \right) ^{j-k}}\sum_{0\le i\le n}{k^i}} \\ \text{注意,}\sum_{0\le i\le n}{k^i}\text{可以直接用等比数列求和公式}O\left( 1 \right) \text{计算!} \\ =\sum_{0\le j\le n}{j!\times 2^j\sum_{0\le k\le j}{\frac{\sum_{0\le i\le n}{k^i}}{k!}\times \frac{\left( -1 \right) ^{j-k}}{\left( j-k \right) !}}} \\ \text{这个式子可以卷积} \\ f\left( n \right) =\sum_{0\le j\le n}{j!\sum_{0\le k\le j}{\frac{\left( -1 \right) ^k\sum_{0\le i\le n}{k^i}}{k!}\times \frac{1}{\left( j-k \right) !}}} \\ \\ $$

     

    #include <iostream>
    #include <algorithm>
    #include <cmath>
    using std::cin;
    using std::cout;
    using std::endl;
    
    using int_t = long long int;
    
    const int_t mod = 998244353;
    const int_t g = 3;
    const int_t LARGE = 1 << 20;
    
    int_t power(int_t base, int_t index);
    int_t bitRev(int_t x, int_t size2);
    template <int_t arg = 1>
    void transform(int_t *A, int_t size);
    int_t upper2n(int_t x);
    
    int_t sum(int_t k, int_t n)
    {
        if (k == 1)
            return (n + 1) % mod;
        // if(k==0) return 0;s
        return ((power(k, n + 1) - 1) % mod * power(k - 1, -1) % mod) % mod;
    }
    
    int main()
    {
        int_t n;
        cin >> n;
        static int_t fact[LARGE] = {1};
        for (int_t i = 1; i <= n * 2; i++)
        {
            fact[i] = (fact[i - 1] * i) % mod;
        }
        static int_t A[LARGE];
        static int_t B[LARGE];
        int_t size = upper2n(2 * n + 1);
        for (int_t i = 0; i <= n; i++)
        {
            A[i] = ((sum(i, n)) % mod * power(fact[i], -1) % mod + mod) % mod;
            B[i] = power(fact[i], -1) * power(-1, i) % mod;
            // cout<<A[i]<<" ";
        }
        transform(A, size);
        transform(B, size);
        for (int_t i = 0; i <= size; i++)
            A[i] = A[i] * B[i] % mod;
        transform<-1>(A, size);
        int_t result = 0;
        for (int_t i = 0; i <= n; i++)
        {
            A[i] = A[i] * power(size, -1) % mod * fact[i] % mod * power(2, i) % mod;
            result = (result + A[i]) % mod;
        }
        cout << result << endl;
        return 0;
    }
    
    template <int_t arg = 1>
    void transform(int_t *A, int_t size)
    {
        int_t size2 = log2(size);
        for (int_t i = 0; i < size; i++)
        {
            int_t x = bitRev(i, size2);
            if (x > i)
                std::swap(A[i], A[x]);
        }
        for (int_t i = 2; i <= size; i *= 2)
        {
            int_t mr = power(g, arg * (mod - 1) / i);
            for (int_t j = 0; j < size; j += i)
            {
                int_t curr = 1;
                for (int_t k = 0; k < i / 2; k++)
                {
                    int_t u = A[j + k];
                    int_t t = A[j + k + i / 2] * curr % mod;
                    A[j + k] = (u + t) % mod;
                    A[j + k + i / 2] = (u - t + mod) % mod;
                    curr = (curr * mr) % mod;
                }
            }
        }
    }
    
    int_t upper2n(int_t x)
    {
        int_t result = 1;
        while (result < x)
            result *= 2;
        return result;
    }
    
    int_t bitRev(int_t x, int_t size2)
    {
        int_t result = 0;
        for (int_t i = 1; i < size2; i++)
        {
            result |= (x & 1);
            x >>= 1;
            result <<= 1;
        }
        return result | (x & 1);
    }
    int_t power(int_t base, int_t index)
    {
        base = (base % mod + mod) % mod;
        if (index < 0)
        {
            index *= -1;
            base = power(base, mod - 2);
        }
        int_t result = 1;
        while (index)
        {
            if (index & 1)
            {
                result = result * base % mod;
            }
            base = base * base % mod;
            index >>= 1;
        }
        return result;
    }