zoukankan      html  css  js  c++  java
  • 【luogu P6860】象棋与马(数学)(杜教筛)

    象棋与马

    题目链接:luogu P6860

    题目大意

    给你一个数 n,然后问你有多少个 a<=n,b<=n 满足在一个二维网格上从源点出发每次走一个 a*b 的矩阵,能走到图上的所有整点。

    思路

    首先考虑怎样的点对是满足条件的。

    首先我们考虑如果它能从 ((0,0)) 走到 ((0,1)),那它就能走到所有点。(因为你可以一步一步走)

    那接着考虑怎么搞,首先顺序无关,所以我们可以把它分成两段位移:((pm x,pm y))((pm y,pm x))

    然后第一段的整体位移可以表示成 ((2ax,2by)) 或者 ((2ax+x,2by+y)),第二段就是 ((2cy,2dx))((2cy+y,2dx+x))

    考虑列出四种可能的方法:
    (left{egin{matrix} 2ax=2cy \ 2by=2dx+1 end{matrix} ight.)

    (left{egin{matrix} 2ax+x=2cy \ 2by+y=2dx+1 end{matrix} ight.)

    (left{egin{matrix} 2ax=2cy+y \ 2by=2dx+x+1 end{matrix} ight.)

    (left{egin{matrix} 2ax+x=2cy+y \ 2by+y=2dx+x+1 end{matrix} ight.)

    然后解四个方程,第一是 (2(ax-cy)=0,2(by-dx)=1),由于 (x,y) 互质,所以 (by-dx) 会可以是任意整数(设为 (k) 下同):
    (2k=0,2k=1),无解

    第二个是跟上面差不多,就是 (2k+x=0,2k+y=1),那就是 (x) 是偶数,(y) 是奇数。

    第三个就是 (2k-y=0,2k-x=1),那就是 (y) 是偶数,(x) 是奇数。

    第四个是 (2k+x-y=0,2k+y-x=1),那就是无解。

    那综上,我们可以总结出合法的情况:
    (gcd(i,j)=1),且 (i+j) 是奇数。


    然后考虑如何继续求,那 (i+j) 是奇数,(i-j) 自然也是。
    然后根据辗转相减法:(gcd(i,j)=1) 就有 (gcd(i,i-j)=1)
    你考虑设 (i>j)(到时算出来答案乘 (2),因为显然 (i=j) 是不成立)

    (sumlimits_{i=1}^nsumlimits_{j=1}^{i-1}2[(gcd(i,j)=1)&((i-j)mod 2=1)])

    然后发现如果不看奇偶它就是 (sumlimits_{i=1}^nvarphi(i)),那你考虑有了右边之后会怎么样。
    考虑这个新的值是 (w(i))
    (原来的式子变成:(sumlimits_{i=1}^n2w(i))

    考虑从 (varphi(i)) 的性质考虑,如果 (i) 是偶数,那所有偶数跟它都不是互质的,那这个操作就不会影响,所以 (w(i)=varphi(i))
    如果 (i) 是奇数,那我们考虑一个东西,就是这个互质的对称性。
    什么意思呢,就是如果 (i,j) 互质((i>j)),那么 (i,i-j) 也互质。

    那我们就其实可以看做是 (w(i)=dfrac{varphi(i)}{2}),当然你会发现 (w(1)) 要特判掉。(应该是 (0) 而不是 (dfrac{1}{2})
    (其实可以不特判,然后到时答案减 (1) 即可,减一是因为后面乘 (2)

    然后你就可以列出 (w(i)=left{egin{matrix}varphi(i)&imod2=0 \ dfrac{varphi(i)}{2}&imod2=1end{matrix} ight.)

    然后把 (2) 放进去:
    (2w(i)=left{egin{matrix}2varphi(i)&imod2=0 \ varphi(i)&imod2=1end{matrix} ight.)
    (2w(i)=varphi(i)+left{egin{matrix}varphi(i)&imod2=0 \ 0&imod2=1end{matrix} ight.)

    然后放回原来的式子:
    (sumlimits_{i=1}^n2w(i))
    (sumlimits_{i=1}^nvarphi(i)+sumlimits_{i=1}^nleft{egin{matrix}varphi(i)&imod2=0 \ 0&imod2=1end{matrix} ight.)

    那我们再看右边的部分,那只看有值的,就是偶数的。
    然后再从递推式求的方式来看 (dfrac{i}{2}),如果它是偶数那返回的就是 (varphi(dfrac{i}{2})),否则就是 (dfrac{varphi(frac{i}{2})}{2}),你会发现它就是 (w(leftlfloordfrac{i}{2} ight floor)) 的值。

    然后就有:
    (sumlimits_{i=1}^nw(i)=sumlimits_{i=1}^nvarphi(i)+sumlimits_{i=1}^{leftlfloorfrac{i}{2} ight floor}w(i))
    左边的用杜教筛,右边的递归下去就好了。

    复杂度是 (O(n^{frac{2}{3}}log n)),看似很危,但其实跑不满(每次递归的 (n) 越来越小)可以过。

    代码

    #include<map>
    #include<cstdio>
    #define ll unsigned long long
    
    using namespace std;
    
    //const ll Maxn = 21544346.900318837217592935665195;
    const ll Maxn = 22000000;
    int T;
    ll n, ans, phi[Maxn + 1], prime[Maxn / 10];
    bool np[Maxn + 1];
    map <int, ll> ans_phi;
    
    void init() {//phi 的预处理
    	phi[1] = 1;
    	for (int i = 2; i <= Maxn; i++) {
    		if (!np[i]) {
    			phi[i] = i - 1; prime[++prime[0]] = i;
    		}
    		for (int j = 1; j <= prime[0] && i * prime[j] <= Maxn; j++) {
    			if (i % prime[j]) phi[i * prime[j]] = phi[i] * (prime[j] - 1), np[i * prime[j]] = 1;
    				else {
    					phi[i * prime[j]] = phi[i] * prime[j], np[i * prime[j]] = 1;
    					break;
    				}
    		}
    	}
    	for (int i = 1; i <= Maxn; i++) phi[i] += phi[i - 1];
    } 
    
    ll get_phi(ll n) {//杜教筛
    	if (n < Maxn) return phi[n];
    	if (ans_phi[n]) return ans_phi[n];
    	ll re = (n & 1llu) ? (1llu + n) / 2llu * n : n / 2llu * (1llu + n);
    	for (ll l = 2, r; l <= n; l = r + 1) {
    		r = n / (n / l);
    		re -= (r - l + 1) * get_phi(n / l);
    	}
    	return ans_phi[n] = re;
    }
    
    ll F(ll n) {
    	if (!n) return 0;
    	return get_phi(n) + F(n / 2);
    }
    
    int main() {
    	init();
    	
    	scanf("%d", &T);
    	while (T--) {
    		scanf("%llu", &n);
    		printf("%llu
    ", F(n) - 1llu);
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    MySQL命令 导出 数据和结构
    Maven web 项目工程的建立
    Maven的配置以及Eclipse的设置
    项目管理工具Maven的安装
    centos7 安装 redis
    Java + 腾讯邮箱 SSL加密问题 重要通知
    centos7 上配置Javaweb---MySQL的安装与配置、乱码解决
    关于阿里云Centos服务器搭建Java网站不能访问的问题
    浏览器使用经验
    Linux常用命令大全
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/luogu_P6860.html
Copyright © 2011-2022 走看看