zoukankan      html  css  js  c++  java
  • 【BZOJ3817】Sum(类欧几里得算法)

    点此看题面

    大致题意:(sum_{i=1}^n(-1)^{lfloor dsqrt r floor})

    前言

    先花了(4)个多小时去学习类欧几里得算法,然后回来看这题。

    本以为至少能推出点啥东西来的,结果依旧是一脸懵逼。

    果然数学太差,看来我是真的菜。

    一个巧妙的转化

    观察题目中给出的式子,其中(lfloor dsqrt r floor)放在指数的位置,看起来非常棘手。

    因此我们考虑对((-1)^x)构造一个等价的函数,只要满足当(x)为奇数时值为(-1)(x)为偶数时值为(1)即可。

    于是我们就得到这样一个函数:(1-2(x\%2))。(这或许可以当作一个套路?)

    众所周知,(x\%2=x-2lfloorfrac x2 floor)。再把这个东西代回原式,得到:

    [sum_{i=1}^n(1-2(lfloor dsqrt r floor-2lfloorfrac{dsqrt r}2 floor))=n-2sum_{i=1}^nlfloor dsqrt r floor+4sum_{i=1}^nlfloorfrac{dsqrt r}2 floor ]

    接下来,就是类欧几里得算法的应用了。

    类欧几里得算法

    刚做了板子完全不知道类欧几里得算法该如何应用的我,真的是一脸懵逼。

    类欧几里得算法一般是用来求解形如(sumlfloorfrac{ai+b}c floor)的式子的,而这题当中虽然没有这种式子,但却有下取整符号。

    于是我们就要考虑去构造一个这种形式的式子。

    为了得到上面这种形式的式子,我们设:

    [f(n,a,b,c)=sum_{i=1}^nlfloor{i imes frac{asqrt r+b}c} floor ]

    (则显然有(sum_{i=1}^nlfloor dsqrt r floor=f(n,1,0,1),sum_{i=1}^nlfloorfrac{dsqrt r}2 floor=f(n,1,0,2))

    考虑如何求出(f(n,a,b,c)),此时按照类欧几里得算法的套路,我们要分类讨论。

    分类讨论:(frac{asqrt r+b}cge 1)

    此时设(p=lfloorfrac{asqrt r+b}c floor),则我们可以从原式中提取(p),得到:

    [egin{align}f(n,a,b,c)&=sum_{i=1}^n(lfloor i imes(frac{asqrt r+b}c-p) floor+i imes p)\&=sum_{i=1}^nlfloor i imesfrac{asqrt r+b-c imes p}c floor+frac{n(n+1)}2 imes p\&=f(n,a,b-c imes p,c)+frac{n(n+1)}2 imes pend{align} ]

    也就是说,这种情况必然能够转化为(0<frac{asqrt r+b}c<1)的情况。

    分类讨论:(0<frac{asqrt r+b}c<1)

    好玄学的做法,运用了函数思想的转化。

    如图所示,考虑(sum_{i=1}^nlfloor dsqrt r floor)其实可以看作是一个类似于积分的形式。

    但与积分不同的是,它求的是一部分区域中整点的个数。

    然后我们既然把它转化成了图像,则(f(n,a,b,c))的意义就变成了正比例函数(y=frac{asqrt r+b}{c}x)(即图中的直线(OA))在(x∈[1,n])时整点的个数(即图中(△AOM)中整点的个数)。

    直接求显然不好求,于是我们需要进一步转化。

    考虑做出(y)反函数(y'=frac c{asqrt r+b}x)(即图中的直线(OB)),那么我们要求的就变成了图中(△BON)中整点的个数。

    或许你会说,这和原来的东西并没有啥区别,一样难求。但实际上,此时我们就可以容斥了。

    已知(ON=OM=n)(OC=AM=frac{asqrt r+b}cn),显然在横坐标不为整数时不可能有整点。

    也就是说我们作直线(B'C':x=lfloorfrac{asqrt r+b}cn floor),则矩形(BCC'B')中不可能有整点。

    然后我们再去看这张图,就会发现,(△BON)中整点的个数实际上等于矩形(ONB'C')中整点的个数减去(△OC'D)中整点的个数(注意由于这是一个斜率是无理数的正比例函数,直线上不可能存在整点,因此不会有问题)。

    (△OC'D)中整点的个数,实际上就是正比例函数(y=frac c{asqrt r+b}x)(x∈[1,lfloorfrac{asqrt r+b}cn floor])时整点的个数。

    (frac c{asqrt r+b})分母有理化可得(frac{acsqrt r-bc}{a^2r-b^2})(这个相信大家都会),也就是说,(△OC'D)中整点的个数即为(f(lfloorfrac{asqrt r+b}cn floor,ac,-bc,a^2r-b^2))

    这样一来,只要通过递归的形式,就能求出答案了。

    还有一些细节问题可以看代码。

    其实我写题解前还只是半懂,写完这篇题解之后就彻底理解了。。。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define LL long long
    using namespace std;
    int n,r;
    Tp I Ty gcd(Con Ty& x,Con Ty& y) {return y?gcd(y,x%y):x;}//求gcd,避免爆long long
    I LL Get(CI n,LL a,LL b,LL c)//求f(n,a,b,c)
    {
    	if(!n) return 0;LL g=gcd(gcd(a,b),c);a/=g,b/=g,c/=g;
    	LL p=(a*sqrt(r)+b)/c;if(p) return 1LL*n*(n+1)/2*p+Get(n,a,b-c*p,c);//如果大于1,提取整数部分转化为小于1的情况
    	int k=(a*sqrt(r)+b)/c*n;return 1LL*k*n-Get(k,a*c,-b*c,a*a*r-b*b);//否则容斥
    }
    int main()
    {
    	RI Tt;scanf("%d",&Tt);W(Tt--)
    	{
    		scanf("%d%d",&n,&r);
    		if((int)sqrt(r)*(int)sqrt(r)==r) {printf("%d
    ",(r&1)?(n&1?-1:0):n);continue;}//特判完全平方数,听说不然会挂
    		printf("%d
    ",n-2*Get(n,1,0,1)+4*Get(n,1,0,2));
    	}return 0;
    }
    
  • 相关阅读:
    bzoj3109【CQOI2013】新数独
    HDU 1015 Safecracker(第一次用了搜索去遍历超时,第二次用for循环能够了,思路一样的)
    从头认识java-15.1 填充容器(3)-填充Map
    写一个python的服务监控程序
    javaScript定义函数的三种方式&amp;变量的作用域
    android开发中应该注意的问题
    某技术大牛的帖子(android项目总结)
    android命名规范
    GitHub使用教程for Eclipse
    Android内存性能优化(内部资料总结)
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ3817.html
Copyright © 2011-2022 走看看