Scx117
只一眼,便辽阔了时间。

题意:给你n,r,求sigma_i=[1,n] (-1)^[i*r^0.5].

n<=1e9.

 

标程:

 1 #include<cstdio>
 2 #include<cmath>
 3 using namespace std;
 4 int read()
 5 {
 6    int x=0,f=1;char ch=getchar();
 7    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
 8    while (ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
 9    return x*f;
10 }
11 double x;
12 int n,r;
13 int gcd(int x,int y) {return (!y)?x:gcd(y,x%y);}
14 int solve(int n,int a,int b,int c)//sigma_i=[1,n] ([(bx+c)/a*i])
15 {
16     if (!n) return 0;
17     int k=gcd(a,gcd(b,c));a/=k,b/=k,c/=k;//最简分式,避免爆int 
18     k=(b*x+c)/a; int sum=n*(n+1)/2*k; c-=k*a;//去掉整数部分,使得k<1 
19     k=(b*x+c)/a*n;//纵坐标范围 
20     return sum+n*k-solve(k,b*b*r-c*c,a*b,-a*c);//下一层递归,分母有理化 
21 }
22 int main()
23 {
24     int T=read();
25     while (T--)
26     {
27         n=read();r=read();x=sqrt(r);
28         if ((int)x==x) printf("%d\n",(r&1)?((n&1)?-1:0):n);//直接算x为有理数的情况
29         else printf("%d\n",n+4*solve(n,2,1,0)-2*solve(n,1,1,0));
30     }
31    return 0;
32 }

 

题解:类欧几里得

solution1:设x=r^0.5.那么x>2时,x-=2奇偶性不变。如果1<x<2,x=2-x,奇偶性不变。所以只用考虑x<1时的情况。因为x*1/x=1,所以i每增加1/x,会改变一次(-1)的正负状态。以1/x为单位长度对1~n的序列轮流黑白染色,整点上黑色-白色的数量即为最后的答案。每一段至少会有[1/x]个整点,不妨把每一段中[1/x]的整数区间抵消(最后一块如果为黑就暴力加贡献,还有多余的部分),然后对{1/x}的单位长度,大致是{1/x}*n/([1/x])大小的区间继续递归。时间复杂度logn。

solution2:

一般情况的类欧算法用于解决求sigma_i=[1,n]([(bx+c)/a*i])的问题,a,b,c都是自定义的常数,x必须是无理数。

设k=(bx+c)/a。那么就相当于求sigma([ki])。也就是横坐标从1到n,y=ki的直线下方、x轴上方包含多少个整数点。k>1,可以对整数部分直接统计。考虑k<1。对于每一条y=j(j<=[kn]),这一条直线上包含在给定区间上的n-[j/k]个点(根据相似,一共有[(kn-j)/kn*n]+1=[n-j/k]+1=n-[j/k]个(k为无理数,不考虑边界))。子问题:求sigma_j=[1,[k/n]] ([j/k])。把1/k的分母有理化一下,就可以递归求解。时间复杂度log^2(n),递归+gcd约分。

 

posted on 2018-04-04 14:52  Scx117  阅读(112)  评论(0编辑  收藏  举报