zoukankan      html  css  js  c++  java
  • JZOJ4367. 【GDKOI2016】小学生数学题(数论推理+自然数幂和)

    https://gmoj.net/senior/#main/show/4367

    题解:

    退役前来了结这个OI入(弃)坑题吧。

    (sum_{i=1}^n frac{1}{i} (~mod~p^k))

    类似于扩展Lucas,把(p)的倍数和不是(p)的倍数分开。

    (= frac{1}{p} sum_{i=1}^{n/p} frac{1}{i} + sum_{i=n/p*p+1}^n frac{1}{i} + sum_{i=0}^{n/p-1}sum_{j=1}^{p-1} frac{1}{ip+j})

    这题保证最后分数有逆元,所以第一部分可直接递归((n/p,p^{k+1}))然后除以(p)即可。

    第二部分(<p),所以暴力逆元即可。

    现在看第三部分:

    (sum_{i=0}^{n/p-1}sum_{j=1}^{p-1} frac{1}{ip+j})
    (=sum_{i=0}^{n/p-1}sum_{j=1}^{p-1} j^{-1}frac{1}{ipj^{-1}+1})

    (i=0)时,后面(=sum_{j=1}^{p-1} j^-1),好算。

    (sum_{i=1}^{n/p-1}sum_{j=1}^{p-1} j^{-1}frac{1}{ipj^{-1}+1})

    生成函数中有(frac{1}{1-x}=sum_{qge 0} x^q),所以:

    (=sum_{i=1}^{n/p-1}sum_{j=1}^{p-1} j^{-1}frac{1}{1-(-ipj^{-1})})
    (=sum_{i=1}^{n/p-1}sum_{j=1}^{p-1} j^{-1} sum_{qge 0} (-ipj^{-1})^q)

    因为里面有(p),所以当(q ge k)时,一定是(0),缩小(q)的循环范围,

    (=sum_{i=1}^{n/p-1}sum_{j=1}^{p-1} j^{-1} sum_{q=0}^{k-1} (-ipj^{-1})^q)
    (sum_{j=1}^{p-1} j^{-1} sum_{q=0}^{k-1} (-pj^{-1})^q sum_{i=1}^{n/p-1}i^q)

    自然数幂和用第二类斯特林数搞搞就好了。

    求逆元用exgcd,需要黑科技乘法。

    分析时间复杂度:

    1. 有一个递归,最多递归(log_p n)层。

    2. 每一层第二部分是(O(kp log p)),第三部分是(O(k^3+pk))

    很明显(O(能过))

    Code:

    #include<bits/stdc++.h>
    #define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
    #define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
    #define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
    #define ll long long
    #define pp printf
    #define hh pp("
    ")
    using namespace std;
    
    ll mul(ll x, ll y, ll mo) {
    	x = (x % mo + mo) % mo, y = (y % mo + mo) % mo;
    	ll z = (long double) x * y / mo;
    	z = x * y - z * mo;
    	if(z < 0) z += mo; else if(z >= mo) z -= mo;
    	return z;
    }
    
    const int N = 505;
    
    ll s[N][N];
    
    ll solve(ll n, ll m, ll mo) {
    	if(m == 0) return n % mo;
    	if(n == 0) return 0;
    	s[0][0] = 1;
    	fo(i, 1, m) fo(j, 1, i) s[i][j] = (s[i - 1][j - 1] + s[i - 1][j] * j) % mo;
    	ll ans = 0;
    	fo(j, 1, m) {
    		ll xs = s[m][j];
    		ll n0 = (n + 1) - (n + 1) % (j + 1);
    		for(ll x = n - j + 1; x < n0; x ++) xs = mul(xs, x, mo);
    		for(ll x = n0 + 1; x <= n + 1; x ++) xs = mul(xs, x, mo);
    		xs = mul(xs, n0 / (j + 1), mo);
    		ans = (ans + xs) % mo;
    	}
    	return ans;
    }
    
    void exgcd(ll a, ll b, ll &x, ll &y) {
    	if(!b) { x = a, y = 0; return;}
    	exgcd(b, a % b, y, x); y -= (a / b) * x;
    }
    
    ll ginv(ll a, ll p) {
    	ll x, y;
    	exgcd(a, p, x, y);
    	return (x % p + p) % p;
    }
    
    ll ksm(ll x, ll y, ll mo) {
    	ll s = 1;
    	for(; y; y /= 2, x = mul(x, x, mo))
    		if(y & 1) s = mul(s, x, mo);
    	return s;
    }
    
    ll dg(ll p, ll k, ll n) {
    	if(n == 0) return 0;
    	
    	ll mo = 1; fo(i, 1, k) mo = mo * p;
    	
    	ll ans = dg(p, k + 1, n / p) / p;
    	for(ll x = n / p * p + 1; x <= n; x ++) ans = (ans + ginv(x, mo)) % mo;
    	
    	static ll t[N];
    	
    	if(n / p > 0) {
    //		fo(i, 0, n / p - 1) fo(j, 1, p - 1)
    //			ans = (ans + ginv(i * p + j, mo)) % mo;
    		fo(q, 0, k - 1) t[q] = solve(n / p - 1, q, mo);
    		fo(j, 1, p - 1)	{
    			ll invj = ginv(j, mo);
    			ans = (ans + invj) % mo;
    			fo(q, 0, k - 1) {
    				ll xs = mul(invj, ksm(-mul(invj, p, mo), q, mo), mo);
    				ans = (ans + mul(xs, t[q], mo)) % mo;
    			}
    		}
    	}
    	ans = (ans % mo + mo) % mo;
    	return ans;
    }
    
    ll p, k, n;
    
    int main() {
    	scanf("%lld %lld %lld", &p, &k, &n);
    	ll ans = dg(p, k, n);
    	pp("%lld
    ", ans);
    }
    
    
  • 相关阅读:
    net 反射30分钟速成
    Net is as typeof 运行运算符详解
    net 自定义泛型那点事
    博客搬家啦!
    Root(hdu5777+扩展欧几里得+原根)2015 Multi-University Training Contest 7
    原根(扩展欧几里得+欧拉函数)
    2015 Multi-University Training Contest 6 solutions BY ZJU(部分解题报告)
    博弈之——SG模板
    点到圆弧的距离(csu1503)+几何
    Integer Partition(hdu4658)2013 Multi-University Training Contest 6 整数拆分二
  • 原文地址:https://www.cnblogs.com/coldchair/p/13404322.html
Copyright © 2011-2022 走看看