zoukankan      html  css  js  c++  java
  • bzoj3309:DZY Loves Math

    Pre

    又是牛顿。

    原来线性筛也是可以癌变成为毒瘤的。

    。。。

    我也不吐槽什么了。(图片有改动,但是大体没变)

    Solution

    式子推完之后,又是一个线性筛,要筛的是。

    (F(n)=sumlimits_{d|n}mu(d)*f(frac{n}{d}))

    (n)唯一分解。

    (n=prodlimits_{i=1}^{k}p_i^{a_i})

    可以证明,如果(a_i eq a_j)

    (F(n)=0)


    证明:

    假设显然有(f(frac{n}{d})=max(a_i)或max(a_i)-1)

    否则莫比乌斯函数的值为0

    从所有的(a_i=max(a_i))的集合中的选择,都可以在(a_i<max(a_i))的集合中找奇偶组数相等。

    这一步是由二项式展开得到的。

    但是展开的要求是集合非空。

    在这道题中就是存在(a_i eq a_j)

    伪证毕(网上的证明没有看懂,所以我自己又写了一篇可能也看不懂的证明)。


    剩下的就好办了。

    除了线性筛。

    所以我们要筛的是(F(n))

    我的代码里面

    (f[])表示函数值

    (g[])表示(p_i)最小的(p_i^{a_i})

    (s[])表示(a_i)

    如果对线性筛极为熟练(就是比我领先一大截的那种),应该很好明白。

    线性筛的性质是一个数被最小的因子筛掉(废话)。

    Code

    #include <bits/stdc++.h>
    #define ll long long
    #define ull unsigned long long
    #define xx first
    #define yy second
    #define mod 100000009
     
    using namespace std;
    const int N = 10000000 + 5, M = 10000000;
    bool vis[N];
    int pri[N], tot;
    ll f[N], g[N], s[N];
    inline void init ();
    
    int main () {
    	init ();
    	int t;
    	scanf ("%d", &t);
    	while (t--) {
    		int a, b;
    		scanf ("%d%d", &a, &b);
    		if (a < b) {
    			swap (a, b);
    		}
    		ll l = 1, r;
    		ll res = 0;
    		while (1) {
    			if (l > b) {
    				break;
    			}
    			r = min (a / (a / l), b / (b / l));
    			res += 1LL * (a / l) * (b / l) * (f[r] - f[l - 1]);
    			l = r + 1;
    		}
    		printf ("%lld
    ", res);
    	}
        return 0;
    }
    
    inline void init () {
    	for (int i = 2; i <= M; ++i) {
    		if (!vis[i]) {
    			pri[++tot] = i;
    			f[i] = 1;
    			g[i] = i;
    			s[i] = 1;
    		}
    		for (int j = 1; j <= tot; ++j) {
    			if (1LL * pri[j] * i > M) {
    				break;
    			}
    			vis[pri[j] * i] = 1;
    			if (i % pri[j] == 0) {
    				s[pri[j] * i] = s[i] + 1;
    				g[pri[j] * i] = g[i] * pri[j];
    				if (pri[j] * i == g[pri[j] * i]) {
    					f[pri[j] * i] = 1;
    				}
    				else {
    					f[pri[j] * i] = s[i * pri[j] / g[i * pri[j]]] == s[i * pri[j]] ? -f[i * pri[j] / g[i * pri[j]]] : 0;
    				}
    				break;
    			}
    			else {
    				f[pri[j] * i] = s[i] == 1 ? -f[i] : 0;
    				g[pri[j] * i] = pri[j];
    				s[pri[j] * i] = 1;
    			}
    		}
    	}
    	for (int i = 1; i <= M; ++i) {
    		f[i] += f[i - 1];
    	}
    }
    

    Conclusion

    注意有些时候前缀和的计算要在循环外面进行,不然会在回溯寻找信息的时候找到错误信息(也可以在回溯的时候通过前缀和进行计算)。

    线性筛感觉跟没学一样。

    线性筛好像有挺大的可拓展性。

  • 相关阅读:
    164 Maximum Gap 最大间距
    162 Find Peak Element 寻找峰值
    160 Intersection of Two Linked Lists 相交链表
    155 Min Stack 最小栈
    154 Find Minimum in Rotated Sorted Array II
    153 Find Minimum in Rotated Sorted Array 旋转数组的最小值
    152 Maximum Product Subarray 乘积最大子序列
    151 Reverse Words in a String 翻转字符串里的单词
    bzoj3994: [SDOI2015]约数个数和
    bzoj 4590: [Shoi2015]自动刷题机
  • 原文地址:https://www.cnblogs.com/ChiTongZ/p/11166638.html
Copyright © 2011-2022 走看看