zoukankan      html  css  js  c++  java
  • [P5172] Sum

    “类欧几里得算法”第一题 sum

    【题意】

    给入(n,r),求(sum_{d=1}^n(-1)^{lfloor dsqrt r floor})

    【分析】

    只需要考虑所有(d)中,(lfloor dsqrt r floor)为偶数的个数。显然(lfloor x floor)为偶数(Leftrightarrow lfloor x floor=2 imeslfloorfrac{x}{2} floor)。 那么原式可以改写为:

    [sum_{d=1}^n 1-2 imes(lfloor dsqrt r floormod 2)=sum_{d=1}^n 1-2 imes(lfloor dsqrt r floor-2 imeslfloorfrac{dsqrt r}{2} floor)\ =n-2 imessum_{d=1}^nlfloor dsqrt r floor+4 imessum_{d=1}^nlfloorfrac{dsqrt r}{2} floor ]

    不妨设(f(a,b,c,n)=sum_{d=1}^nlfloor d imesfrac{asqrt r+b}{c} floor),那么原式即为

    [n-2 imes f(1,0,1,n)+4 imes f(1,0,2,n) ]

    考虑关于(f(a,b,c,n))的算法,(开始扣题了),设(k=frac{asqrt r +b}{c})

    (kge1)时,(k)可以拆为一个正数+小于1的非负实数,即

    [f(a,b,c,n)=sum_{d=1}^n lfloor d imes k floor=sum_{d=1}^n d imeslfloor k floor+lfloor d imes(k-lfloor k floor) floor\ =frac{n(n+1)}{2}lfloor k floor+sum_{d=1}^nlfloor d imesfrac{asqrt r+b-lfloor k floor imes c}{c} floor\ =frac{n(n+1)}{2}lfloor k floor+f(a,b-lfloor k floor imes c,c,n) ]

    (k<1)时,(比如上面递归的那层),可以看作是满足

    [egin{cases} 0<xle n\ 0<yle x imes k\ xin Z\ yin Z end{cases} ]

    的点数。考虑再矩形((1,1)(n,lfloor n imes k floor))内容斥可得个数为(n imeslfloor n imes k floor) 减去左上三角的部分,而那部分可当作是(y=x imes k, xin[1,n])的反函数(y=x imes dfrac{1}{k}, xin[1,lfloor n imes k floor])

    其中(dfrac{1}{k}=dfrac{c}{asqrt r+b}=dfrac{c(asqrt r-b)}{(asqrt r+b)(asqrt r-b)}=dfrac{acsqrt r-bc}{a^2r-b^2})

    [f(a,b,c,n)=n imeslfloor n imes k floor-f(ac,-bc,a^2r-b^2,lfloor n imes k floor) ]

    可以发现,情况一二交替递归,且每轮的总的变化与欧几里得算法相似,故知其复杂度为(log​)级的。

    难度海星。。

    然而当(r)为完全平方数时需要单独算,大概会爆LL吧。。

    #include <bits/stdc++.h>
    #define LL long long
    using namespace std;
    LL n,r;
    double x;
    LL f(LL a,LL b,LL c,LL n) {
    	if(!n) return 0;
    	LL d=__gcd(__gcd(a,b),c);
    	a/=d, b/=d, c/=d;
    	double k=(a*x+b)/c;
    	if(k>=1) return n*(n+1)/2*(LL)(k)+f(a,b-(LL)(k)*c,c,n);
    	else return n*(LL)(n*k)-f(a*c,-b*c,a*a*r-b*b,(LL)(n*k));
    }
    int main() {
    	int T;
    	scanf("%d",&T);
    	while(T--) {
    		scanf("%lld%lld",&n,&r);
    		x=sqrt(r);
    		LL c=x;
    		if(c*c==r) {
    			if(c&1) printf("%lld
    ",n-2*((n+1)/2));
    			else printf("%lld
    ",n);
    		} 
    		else printf("%lld
    ",n-2*f(1,0,1,n)+4*f(1,0,2,n));
    	}
    	return 0;
    }
    
  • 相关阅读:
    poj 2411 Mondriaan's Dream 骨牌铺放 状压dp
    zoj 3471 Most Powerful (有向图)最大生成树 状压dp
    poj 2280 Islands and Bridges 哈密尔顿路 状压dp
    hdu 3001 Travelling 经过所有点(最多两次)的最短路径 三进制状压dp
    poj 3311 Hie with the Pie 经过所有点(可重)的最短路径 floyd + 状压dp
    poj 1185 炮兵阵地 状压dp
    poj 3254 Corn Fields 状压dp入门
    loj 6278 6279 数列分块入门 2 3
    VIM记事——大小写转换
    DKIM支持样本上传做检测的网站
  • 原文地址:https://www.cnblogs.com/nosta/p/10299183.html
Copyright © 2011-2022 走看看