UVA-12716 GCD+异或运算性质+约数筛法

GCD XOR
Description:
输入一个整数n,有多少对整数(a,b)满足 1≤b≤a≤n, g c d ( a , b ) = = a X O R b gcd(a,b)==a XOR b
思路历程:
①暴力循环 时间复杂度O(n^2),毫无疑问会超时。

②考虑到(虽然自己一开始不知道)
a X O R b = c , t h e n aXORb=c,then , a X O R c = b aXORc=b
令c=gcd(a,b),或者 c 必然是a的约数,所以枚举a,c,用 a XOR c算出b,再检验 gcd(a,b)==c。时间复杂度O(nlognlogn
ps:一开始还想着用vector<int> facotr[] 去存储枚举的a的正约数集合,发现编译都通不过(数组太大了)
但是,这样还是TLE。还是得优化。


g c d ( a , b ) a b a X O R b a > b gcd(a,b)≤a-b≤aXORb\qquad a>b
g c d ( a , b ) = a X O R b = c gcd(a,b)=aXORb=c
由上面的式子得, a b = c a-b=c ,于是还是枚举a,c,用a-b=c算出b,再检验
a XOR b == c。
时间复杂度:O(n*logn)

int t,n;
int ncase=0;
int main(){
    cin>>t;
    while(t--)
    {
        ll ans=0;
        scanf("%d",&n);
        int a,b,c;
        for(c=1;c<=n;c++)
        {
            for(int k=2;k<=n/c;k++)
            {
                
                a=k*c;
                b=a-c;
                if(c==(a^b))
                {
                    ans++;
                }
            }
        }
        printf("Case %d: %lld\n",++ncase,ans);
    }
    return 0;
}

但是,还是TLE!
题目要求测试量可达10000,整体时间复杂度O(Tnlogn)

④依照用空间换时间的想法。
时间复杂度:O(n*logn+T)

#include<stdio.h>
#include<iostream>
#include<cmath>
#include<math.h>
#include<string>
#include<string.h>
#include<algorithm>
#include<queue>
#include<vector>
#define ms0(a) memset(a,0,sizeof(a))
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 3e7;
int t,n;
int ncase=0,num[maxn+10];
void init()
{
    for(int c=1;c<=maxn/2;c++)
    {
        for(int a=2*c;a<=maxn;a+=c)
        {
            if((a^(a-c))==c)
                num[a]++;
        }
    }
    for(int i=2;i<=maxn;i++)
        num[i]+=num[i-1];
}
int main(){
    cin>>t;
    init();
    while(t--)
    {
        scanf("%d",&n);
        printf("Case %d: %d\n",++ncase,num[n]);
    }
    return 0;
}

num[n] 一开始存放的是在 a=n 时,满足1≤b≤a 且满足 g c d ( a , b ) = = a X O R b gcd(a,b)==a XOR b 的数对的对数。
当然题目要求的是小于某个数n的数对的个数,也就说
n u m [ n ] = k = 1 n n u m [ k ] num[n]=\sum_{k=1}^n num[k]

ps:用倍数法枚举正约数

    for(int c=1;c<=maxn/2;c++)
    {
        for(int a=2*c;a<=maxn;a+=c)
        {
        //...... c是a的约数
        }
    }

或者

    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n/i;j++)
        {
        //......  i是i*j 的约数
        }
    }
发布了67 篇原创文章 · 获赞 0 · 访问量 1527

猜你喜欢

转载自blog.csdn.net/qq_44846324/article/details/104502714
今日推荐