BestCoder #Valentine's Day Round 1002 || hdu 5175

这里写图片描述

题目大意

给定一个数N,求满足gcd(n,m)==n xor m的所有m.(1<=m<=n)
其中1<=n<=10^10

解题思路

首先,由于n很大,直接枚举m(from 1 to n)肯定会超时;
那我们就枚举gcd(n,m)了,所有可能的结果是n的约数,这一步就涉及到整数分解;有了gcd了,要求m,m一定是gcd的倍数,枚举m,判断是否满足等式,超时!!!!!
原因是找gcd的倍数的时间复杂度太高,能不能换换思路?枚举gcd的思路不可能再变了,那么能不能变一下恒等式……

百度百科这里写图片描述(很容易理解)

根据亦或运算的性质,原等式等价于m==n xor gcd(n,m),原问题转换为找出所有的m使得m==n xor gcd(n,m),所以先将n xor gcd ,再判断亦或结果可不可以认为是m(1<=m<=n且n,m的最大公约数==gcd),满足就记录下来。
当然,整数分解时约数是1、n的可以先不考虑,最后只要n是奇数且n>1,就把n-1记录下来,证明过程也很好理解:
如果gcd(n,m)=n,则n^m=n^n=0!=gcd(n,m),约数是n不对!
如果gcd(n,m)=1, 则n^m要想等于1,根据异或运算相同为0不同为1,n为奇数且n=m-1才能满足,所以要特判一下!
不过按理来说n的约数是有1和n的,所以整数分解时i从1开始循环便可以得到所有约数,最后也不用特判1,n了。

参考代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <map>
#include <vector>
#include <cstring>
#include <cmath>
#include<limits.h>
#define eps 1e-8
using namespace std;
typedef long long ll;
const int maxx=INT_MAX;
const int maxn = 1e5+10;
const ll Max=1e10;
ll n,temp,fac[maxn],ans[maxn],k;
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
void divide()//整数分解得到所有约数
{
   k=0;
   for(ll i=2;i*i<=n;i++)//约数没有1,n,最后特判一下
   if(n%i==0){
    fac[k++]=i;
    if(i*i<n) fac[k++]=n/i;
   }
   return;
}
int main()
{
  // freopen("input.txt","r",stdin);
   int cnt=1;
   while(cin>>n){
    printf("Case #%d:\n",cnt++);
    divide();
    ll t=0;
    for(ll i=0;i<k;i++){
        temp=n^fac[i];//n ^ gcd 的结果temp 
        if(gcd(n,temp)==fac[i]&&temp<n&&temp) ans[t++]=temp;//判断temp==m?
    }
   if(n&1&&n>1) ans[t++]=n-1;//n为非1的奇数(1==n),特判1
    sort(ans,ans+t);
    cout<<t<<endl;for(ll i=0;i<t;i++) i==0?printf("%lld",ans[i]):printf(" %lld",ans[i]);puts("");
   }
   return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值