51nod 算法马拉松35 E

有这样一段两两求最大公约数的程序CoGcd,

int Gcd(int x, int y){
   if(y == 0)return x;
   return Gcd(y, x % y);
}

void CoGcd(int m){
   for(int i = 1; i <= m; i++)
       for(int j = 1; j <= m; j++)
           Gcd(i, j);
}

给出m的值,进行t次询问,每次询问包含一对xi,yi。针对每次询问,输出整个程序执行过程当中,Gcd(xi, yi)被执行了多少次。

例如:\(m = 20\),

\(Gcd(8,5)\)会被执行4次,对应的x, y值是

(8,5) (5,8) (13,8) (8,13),这4组x y,在调用Gcd时,会递归执行Gcd(8, 5)。

sol

考虑二元组\((a,b)\),\(a>b\),在一次操作之后是该二元组一定是\((ka+b,a)\)的形式。

考虑二元组\((a,a+b)\),之后每次操作形如:
\[
(x,y) \to (x+y,y)
\(x,y) \to (x,x+y)
\]
不难发现这样的操作与取模操作的逆运算一一对应(一个是让\(k=k+1\),另一个是换方向\(k=1\))。

并且这样找出来的二元组不会重复。

考虑用二元组(x,y)表示一个数\(ax+(a+b)y\)。显然合法的\(x,y\)是所有\(\gcd(x,y)=1\)。

并且每一个\((x,y)\)只会作为最大值出现2次。

问题即求:
\[
\begin{aligned}
\sum _{x,y} [\gcd(x,y)=1][ax+(a+b)y\le m]
\=\sum _d \mu(d) \sum _{x,y} [ax+(a+b)y \le \lfloor\frac {m}{d}\rfloor]
\\end{aligned}
\]

杜教筛 + 类欧几里得即可。

复杂度\(O(T\sqrt m\log m + m^\frac 23)\)

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e6+6;
int mu[N], prime[N], pcnt, vis[N];
inline void sieve(int n = 5e6){
    mu[1] = 1;
    for(int i=2;i<=n;i++){
        if(!vis[i])prime[++pcnt]=i,mu[i]=-1;
        for(int j=1;j<=pcnt&&1ll*i*prime[j]<=n;j++){
            vis[i*prime[j]] = 1;
            if(i%prime[j])mu[i*prime[j]] = -mu[i];
            else {
                mu[i*prime[j]]=0;
                break;
            }
        }
    }
    for(int i=1;i<=n;i++)mu[i] += mu[i-1];
}
ll query(ll n, ll a, ll b, ll c) {
    ll x = a / c, y = b / c;
    if (!a) {
        return y * (n + 1);
    }else if (a >= c || b >= c) {
        return query(n, a % c, b % c, c) + n * (n + 1) / 2 * x + (n + 1) * y;
    } else {
        ll m = (1ll * a * n + b) / c;
        return n * m - query(m - 1, c, c - b - 1, a);
    }
}
map<int,int> MU;
inline int q1(int n){
    if(n<=5000000)return mu[n];
    if(MU.find(n)!=MU.end())return MU[n];
    int ans = 1;
    for(int u=2,v;u<=n;u=v+1){
        v=n/(n/u);
        ans -= (v-u+1)*q1(n/u);
    }
    return MU[n]=ans;
}
inline ll q(int a,int b,int n){
    int d = n/a;
    int t = n%a;
    return query(d-1,a,t,b);
}
ll ans = 0;
int t,m;
inline void find(int x,int y){
    if(x>m||y>m)return;
    ans+=2;
    find(x+y,y),find(x,y+x);

}

int main()
{
    cin >> t >> m;
    sieve();
    while(t--){
        ans = 0;
        int a,b;
        scanf("%d%d",&a,&b);
        if(a<=b){puts("1");continue;}
        b+=a;
        if(b>m){puts("2");continue;}
        ans = 4;
        for(int u=1,v;u<=m;u=v+1){
            v=m/(m/u);
            int f1 = q1(v) - q1(u-1);
            ans += 4ll*f1*q(a,b,m/u);
        }
        printf("%lld\n",ans);
    }
}

原文地址:https://www.cnblogs.com/weiyanpeng/p/11623594.html

时间: 2024-08-06 20:09:59

51nod 算法马拉松35 E的相关文章

51nod 算法马拉松35(A-D)

挺好玩的一场比赛. 链接 A 打表,打到\(2e4\)左右会发现有一个长度\(104\)的循环节. #include<bits/stdc++.h> using namespace std; int col[5010][5010]; int dx[4] = {1,0,-1,0},dy[4] = {0,1,0,-1}; long long n,tem=0; int main() { cin >> n; int x=0,y=0,d=0; while(tem<n){ ++tem; x

51Nod 算法马拉松21(迎新年)

这次打算法马拉松是在星期五的晚上,发挥还算正常(废话,剩下的题都不会= =). 讲讲比赛经过吧. 8:00准时发题,拿到之后第一时间开始读. A配对,看上去像是二分图最大权匹配,一看范围吓傻了,先跳过读后面的题. B完全二叉树的方差,大概看了一遍,好神的样子,跳过. C多项式?好吧没学过FFT和NTT的我肯定不会,跳跳跳. D最大值,哎呦这函数什么破玩意儿,看不懂,跳跳跳. E B君的射击,卧槽毕克大人您出题就算了出这么一道码农题是要闹那样,跳跳跳. F那些年,我们一起讲的故事,卧槽这特么简直就

随便玩玩系列之一:SPOJ-RNG+51nod 算法马拉松17F+51nod 1034 骨牌覆盖v3

先说说前面的SPOJ-RNG吧,题意就是给n个数,x1,x2,...,xn 每次可以生成[-x1,x1]范围的浮点数,把n次这种操作生成的数之和加起来,为s,求s在[A,B]内的概率 连续形的概率,想象为一个n维长方体,有两个平面与这个几何图形相割,于是就变成了求面(体)积问题,一般要去重,n维区域系数:s^n/n!,至于区间问题,直接前缀之差搞定 然后就是悲催的算法马拉松17F题了...其实是道好题来的,只是出题人不知世界上还有这题,然后某大牛把思路理清后把答案直接搬了过来 经典的1*2骨牌覆

51Nod 算法马拉松15 记一次悲壮而又开心的骗分比赛

OwO 故事的起源大概是zcg前天发现51Nod晚上有场马拉松,然后他就很开心的过去打了 神奇的故事就开始了: 晚上的时候我当时貌似正在写线段树?然后看见zcg一脸激动告诉我第一题有九个点直接输出B就可以A.. 然后之后zcg以奇怪的二分方式发现了如何A掉第一题的第十个点(我记得貌似是什么第5000个数等于511? OwO 就这样没有任何思考含量全凭骗分黑科技过掉了第一题 OwO 然后zcg打开了第二题,发现第二题样例有点问题,然后就发了个帖子,直接去看第三题了 我去瞅了一眼,发现这不是gcd

51nod算法马拉松 contest7

A题 链接:http://www.51nod.com/contest/problem.html#!problemId=1417 推荐链接:http://blog.csdn.net/a837199685/article/details/45009337 设美女取得正面概率是p,反面就是(1-p),就是美女取一正一反和一反一正的概率相同,然后推出公式y=((a+b)/2+b)/(2*(a+b)); 1 #include<iostream> 2 #include<cstdio> 3 #i

51Nod 算法马拉松23 开黑记

惨啊--虽然开了半天黑,但是还是被dalao们踩了-- 第二次开黑,还是被卡在rank20了,我好菜啊--= = 写一写比赛经过吧-- 看到题之后习惯性都打开,A~D看上去似乎并没有什么思路,F应该是道数论题,看了E感觉有点意思,一看数据范围,咦怎么只有$50000$,再仔细看一看式子,手动分情况讨论之后得到一个结论-- 这题是水的线段树维护莫队啊= = 然后就开始码码码,由于一些脑残错误调了一会儿,然后就得到了这样的结果: 我坚信自己莫队的复杂度没错,然后就开始各种王逸松卡常,使用的卡常技巧包

51nod 算法马拉松4

http://www.51nod.com/contest/problemList.html#!contestId=9 D 装盒子 拓扑排序?

51NOD算法马拉松 最大值问题 离线预处理+set lower_bound

题目:http://www.51nod.com/contest/problem.html#!problemId=1349 题意:100000个数的序列,有100000次询问,每次问区间最大值大于等于k的区间有多少? 思路:一开始没看到"大于等于",想了很久也不会,原来看错题了.看错题害死人. 一般询问的问题,如果不能用线段树log(n)求出,那么就离线做. 首先将询问按从大到小排序,再将序列中的每个数排序,注意记录序号. 对于当前询问,每加进一个数,我需要找到它在加进的序列(按大小有序

51nod 算法马拉松4 D装盒子(网络流 / 二分图最优匹配)

装盒子 基准时间限制:1 秒 空间限制:131072 KB 分值: 160 有n个长方形盒子,第i个长度为Li,宽度为Wi,我们需要把他们套放.注意一个盒子只可以套入长和宽分别不小于它的盒子,并且一个盒子里最多只能直接装入另外一个盒子 (但是可以不断嵌套),例如1 * 1 可以套入2 * 1,而2 * 1再套入2 * 2.套入之后盒子占地面积是最外面盒子的占地面积.给定N个盒子大小,求最终最小的总占地面积. Input 第一行一个数N表示盒子的个数. 接下来N行,每行两个正整数,表示每个盒子的长