[atARC123F]Insert Addition

前置知识

下面,先来介绍一下Stern-Brocot Tree的结构:

其是一棵满二叉树,每一个节点都是一个最简分数,其中根为11

假设前i层的中序遍历分数依次为yi,jxi,j(其中i1,j[1,2i),即根为第一层),并令(xi,0,yi,0)=(1,0)(xi,2i,yi,2i)=(0,1),那么第i+1层的从左到右第j个分数为yi,j1+yi,jxi,j1+xi,j(其中j[1,2i]

(特别的,根据定义在i=0时,{(xi,yi)}即仅包含(1,0)(0,1)

根据定义,不难得到有f(xi)=xi+1f(yi)=yi+1,这可以方便理解下面的结论——

性质1:i0,yi,jxi,j构成一个严格单调递增的序列(特别的,定义10=

性质2:xi,yiN,存在i0,j[0,2i)满足(xi,j,yi,j)=(x1,y1)(xi,j+1,yi,j+1)=(x2,y2)当且仅当x1y2x2y1=1

性质3:x,yN,存在i0,j[0,2i]满足(xi,j,yi,j)=(x,y)当且仅当gcd(x,y)=1

性质1和性质2可以归纳得到,性质3可以根据性质2得到,证明过程略

题解

性质4:i0,j[0,2i],有xi,j+yi,ji+1

性质5:i0,j[0,2i],有F(i)({a,b})j=axi,j+byi,j

这两个性质同样可以归纳得到,证明过程略

结合性质1和3,不难得到{Bi}={ax+byx,yN,gcd(x,y)=1ax+byN},并且对应的顺序即按照yx从小到大排序,由此即有一个o(N2logN)的暴力做法

考虑优化,不妨假设gcd(a,b)=1(将N除以gcd(a,b)即可),那么根据裴蜀定理,存在abab=1,并根据通解的形式调整使得a[0,a),进而有b=ab+1a[1,b]

此时,不妨将二元组(x,y)变为(ax+by,ax+by),并对条件分析——

性质6:gcd(x,y)=gcd(ax+by,ax+by)

性质7:y1x1<y2x2等价于ax1+by1ax1+by1<ax2+by2ax2+by2

性质6可以归纳并结合辗转相减法得到,性质7直接展开可得,证明过程略

另外,关于x,yN的条件,将xy用新二元组的(x,y)表示,解得即x,yNaaxybb

综上,问题即求分母在[1,N]中、值在[aa,bb]中的从小到大第[l,r]个最简分数(的分母),此时只需要在之前的Stern-Brocot Tree上二分即可

在过程中,即需要查询子树大小,也即求出值在[x1y1,x2y2]中且分母[1,N]的分数个数

关于这个问题,先将范围差分(即仅考虑x2y2),并对gcd(x,y)=1的条件容斥,即令g(n)为忽略此条件且分母[1,n]的分数个数,那么不难得到答案即d=1Nμ(d)g(Nd)

预处理μ的前缀和后,数论分块即变为求Ng(n)的值,则有g(n)=y=1n(yx2y2+1),可以通过类欧几里得算法计算,时间复杂度为o(logn)

注意到每层只有o(1)次上述查询,因此总共只有o(N)次查询

总复杂度即o(NNlogN+len)(其中len=rl+1),可以通过

(实际上跑不满,常数极小,甚至于一些比较暴力的代码都可以通过)

复制代码
 1 #include<bits/stdc++.h>
 2 #include<atcoder/math>
 3 using namespace std;
 4 #define N 300005 
 5 #define ll long long
 6 #define pii pair<int,int>
 7 #define fi first
 8 #define se second
 9 vector<int>ans;
10 int n,aa,bb,vis[N],p[N],mu[N];
11 ll l,r;
12 pii a,b;
13 bool cmp(pii x,pii y){
14     return (ll)x.fi*y.se<(ll)x.se*y.fi;
15 }
16 ll get_g(pii k,int n){
17     return atcoder::floor_sum(n,k.se,k.fi,k.fi+k.se);
18 }
19 ll get_tot(pii k){
20     if (cmp(k,a))k=a;
21     if (cmp(b,k))k=b;
22     ll ans=0;
23     for(int i=1,j;i<=n;i=j+1){
24         j=n/(n/i);
25         ans+=(ll)(mu[j]-mu[i-1])*get_g(k,n/i);
26     }
27     return ans;
28 }
29 void dfs(pii x,pii y){
30     if ((cmp(b,x))||(cmp(y,a)))return;
31     pii m=make_pair(x.fi+y.fi,x.se+y.se);
32     if (m.se>n)return;
33     dfs(x,m);
34     if ((cmp(a,m))&&(cmp(m,b)))ans.push_back(m.se);
35     dfs(m,y);
36 }
37 void calc(pii x,pii y,ll l,ll r,ll s){
38     if ((cmp(b,x))||(cmp(y,a))||(l>s)||(r<1))return;
39     if ((l<=1)&&(s<=r)){
40         dfs(x,y);
41         return;
42     }
43     pii m=make_pair(x.fi+y.fi,x.se+y.se);
44     ll ss=get_tot(m)-get_tot(x);
45     calc(x,m,l,r,ss-1);
46     if ((l<=ss)&&(ss<=r)&&(cmp(a,m))&&(cmp(m,b)))ans.push_back(m.se);
47     calc(m,y,l-ss,r-ss,s-ss);
48 }
49 int main(){
50     mu[1]=1;
51     for(int i=2;i<N;i++){
52         if (!vis[i]){
53             p[++p[0]]=i;
54             mu[i]=-1;
55         }
56         for(int j=1;(j<=p[0])&&(i*p[j]<N);j++){
57             vis[i*p[j]]=1;
58             if (i%p[j])mu[i*p[j]]=mu[i]*mu[p[j]];
59             else{
60                 mu[i*p[j]]=0;
61                 break;
62             }
63         }
64     }
65     for(int i=1;i<N;i++)mu[i]+=mu[i-1];
66     scanf("%d%d%d%lld%lld",&aa,&bb,&n,&l,&r);
67     int g=__gcd(aa,bb);
68     aa/=g,bb/=g,n/=g;
69     for(int i=0;i<aa;i++)
70         if (((ll)i*bb+1)%aa==0){
71             a=make_pair(i,aa);
72             b=make_pair(((ll)i*bb+1)/aa,bb);
73             break;
74         }
75     if (l>1)l--;
76     else ans.push_back(a.se);
77     r--;
78     pii x=make_pair(0,1),y=make_pair(1,0);
79     calc(x,y,l,r,get_tot(y)-get_tot(x)-1);
80     if (get_tot(y)-get_tot(x)==r)ans.push_back(b.se);
81     for(int i=0;i<ans.size();i++)ans[i]*=g;
82     printf("%d",ans[0]);
83     for(int i=1;i<ans.size();i++)printf(" %d",ans[i]);
84     printf("\n");
85     return 0;
86 }
View Code
复制代码

 

posted @   PYWBKTDA  阅读(128)  评论(2编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示