• Bzoj4816: [Sdoi2017]数字表格


    题面

    戳我

    Sol

    摆公式:
    (ans=Pi_{i=1}^{n}Pi_{j=1}^{m}f[gcd(i, j)])
    考虑每个gcd的贡献,设n < m
    则就是(Pi_{d=1}^{n}Pi_{i=1}^{lfloorfrac{n}{d} floor}Pi_{j=1}^{lfloorfrac{m}{d} floor}f[d]*[gcd(i, j)==1])
    (=Pi_{d=1}^{n}f[d]^{sum_{i=1}^{lfloorfrac{n}{d} floor}sum_{j=1}^{lfloorfrac{m}{d} floor}[gcd(i, j)==1]})
    那个指数幂就是(sum_{i=1}^{lfloorfrac{n}{d} floor}mu[i]*lfloorfrac{n}{di} floor*lfloorfrac{m}{di} floor)
    但指数取模1e9+7显然不行,所以要用到一个欧拉的定理
    降幂法
    如果直接这样搞加了数论分块也会TLE飞
    所以考虑把式子变形一下:(di换成k)
    (Pi_{k=1}^{n}Pi_{d|k} f[d]^{mu[frac{k}{d}]lfloorfrac{n}{k} floorlfloorfrac{m}{k} floor})
    (Pi_{d|k} f[d]^{mu[frac{k}{d}]})预处理出来就好 以为可以筛想了好久

    # include <bits/stdc++.h>
    # define RG register
    # define IL inline
    # define Fill(a, b) memset(a, b, sizeof(a))
    using namespace std;
    typedef long long ll;
    const int _(1e6 + 1), Zsy(1e9 + 7);
    
    IL ll Read(){
        char c = '%'; ll x = 0, z = 1;
        for(; c > '9' || c < '0'; c = getchar()) if(c == '-') z = -1;
        for(; c >= '0' && c <= '9'; c = getchar()) x = x * 10 + c - '0';
        return x * z;
    }
    
    int prime[_], num, mu[_], g[_], f[_], s[_];
    bool isprime[_];
    
    IL int Pow(RG ll x, RG ll y){
    	RG ll ret = 1;
    	for(; y; y >>= 1, x = x * x % Zsy) if(y & 1) ret = ret * x % Zsy;
    	return ret;
    }
    
    IL void Prepare(){
    	isprime[1] = 1; mu[1] = f[1] = g[1] = s[1] = s[0] = 1;
    	for(RG int i = 2; i < _; ++i){
    		if(!isprime[i]){  prime[++num] = i; mu[i] = -1;  }
    		for(RG int j = 1; j <= num && i * prime[j] < _; ++j){
    			isprime[i * prime[j]] = 1;
    			if(i % prime[j]) mu[i * prime[j]] = -mu[i];
    			else{  mu[i * prime[j]] = 0; break;  }
    		}
    		f[i] = (f[i - 1] + f[i - 2]) % Zsy;
    		g[i] = Pow(f[i], Zsy - 2); s[i] = 1;
    	}
    	for(RG int i = 1; i < _; ++i){
    		if(!mu[i]) continue;
    		for(RG int j = i, t = 1; j < _; j += i, ++t)
    			s[j] = 1LL * s[j] * ((mu[i] == 1) ? f[t] : g[t]) % Zsy;
    	}
    	for(RG int i = 1; i < _; ++i) s[i] = 1LL * s[i] * s[i - 1] % Zsy;
    }
    
    int main(RG int argc, RG char *argv[]){
    	Prepare();
    	for(RG ll T = Read(), n, m, ans; T; --T){
    		n = Read(); m = Read(); ans = 1;
    		if(n > m) swap(n, m);
    		for(RG ll k = 1, j; k <= n; k = j + 1){
    			j = min(n / (n / k), m / (m / k));
    			ans = 1LL * ans * Pow(1LL * s[j] * Pow(s[k - 1], Zsy - 2) % Zsy, 1LL * (n / k) * (m / k) % (Zsy - 1)) % Zsy;
    		}
    		printf("%lld
    ", ans);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    【数据结构】算法 Tree Sub Structure 树的子结构
    【数据结构】算法 Binary Search Tree find Kth largest Node 二叉搜索树的第k大节点
    【数据结构】算法 Count Complete Tree Nodes 完全二叉树的节点个数
    【数据结构】算法 合并K个有序链表Merge k Sorted Lists
    JVisualVM 插件安装中出现网络问题
    [ISSUE] Logback TimeBasedRollingPolicy not rolling every day.
    【数据结构】算法 计算数组中的逆序对
    JQ为元素添加class
    时间戳转换成日期
    JS拖拽
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/8274259.html
Copyright © 2020-2023  润新知