1907. Coffee and Buns
Memory limit: 64 MB
Input
Output
Sample
input | output |
---|---|
3 6 | 4 |
Notes
Problem Source: Ural Championship 2012
All submissions (654) All accepted submissions (223) Solutions rating (123)
大致题意:
输入 a n 判断 从 b = 1 ~ n 中 满足 gcd( ( a * a + b * b ) , 4 * a + 4 * b ) > 1 的个数。
a < 1e12 , n < 1e18
若 a b 奇偶性相同,显然满足。gcd是2的倍数。
若a b 奇偶性不同,
开始推导:
因为 a * a + b * b 是奇数,
所以
gcd( a * a + b * b , 4 * a + 4 * b ) > 1 等价于
gcd( a * a + b * b , a + b ) > 1 等价于
根据整除性质,若存在 e > 1 ,满足 e | ( a + b ) , 那么 e | ( a + b ) ^ 2 反之亦然
则等价于
gcd( a * a + b * b , a * a + b * b + 2 * a * b ) > 1 等价于
gcd( 2 * a * a + 2 * b * b , a * a + b * b + 2 * a * b ) > 1等价于
gcd( a * a + b * b - 2 * a * b , a * a + b * b + 2 * a * b ) > 1 等价于
gcd( a - b , a + b ) > 1 等价于
gcd( 2 * a , a + b ) > 1
因为 a+b是奇数
等价于
gcd( a , a +b ) > 1等价于
gcd( a , b ) > 1
推导结束
下面对a分解质因数,找出n个数中不同奇偶性且满足gcd( a , b ) > 1的个数
最后加上 相同奇偶性的 个数 就是答案。
所以要求1~maxn中与a,gcd > 1 的个数,就是求1~maxn与某一个num不互素的个数,要用到容斥原理:
ll no_coprime(ll num,ll MAXN){//1~maxn与num不互素的个数
ll ans = 0;
vector<ll> fac;
for(ll i = 2; i*i <= num; i++){ //分解因数
if( num % i == 0){
fac.push_back(i);
while(num%i == 0) num /= i;
}
}
if(num != 1) fac.push_back(num);
int sz = SZ(fac);
for(ll mask = 1 ; mask < (1LL<<sz); mask++){ //容斥过程,复杂度2^因数个数
ll c = 0;
ll tmp = 1;
rep(i,sz) if( (1LL<<i)&mask){
c++;
tmp *= fac[i];
}
if(c&1) ans += MAXN/tmp;
else ans -= MAXN/tmp;
}
return ans;
}
ac代码:
//Accepted 412 15 G++ 4.9 C++11 2092
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <ctime>
#include <bitset>
#include <algorithm>
#define SZ(x) ((int)(x).size())
#define ALL(v) (v).begin(), (v).end()
#define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i)
#define reveach(i, v) for (__typeof((v).rbegin()) i = (v).rbegin(); i != (v).rend(); ++ i)
#define REP(i,n) for ( int i=1; i<=int(n); i++ )
#define rep(i,n) for ( int i=0; i<int(n); i++ )
using namespace std;
typedef long long ll;
#define X first
#define Y second
typedef pair<ll,ll> pii;
template <class T>
inline bool RD(T &ret) {
char c; int sgn;
if (c = getchar(), c == EOF) return 0;
while (c != '-' && (c<'0' || c>'9')) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
template <class T>
inline void PT(T x) {
if (x < 0) {
putchar('-');
x = -x;
}
if (x > 9) pt(x / 10);
putchar(x % 10 + '0');
}
ll a,n;
ll no_coprime(ll num,ll MAXN){
ll ans = 0;
vector<ll> fac;
for(ll i = 2; i*i <= num; i++){ //分解因数
if( num % i == 0){
fac.push_back(i);
while(num%i == 0) num /= i;
}
}
if(num != 1) fac.push_back(num);
int sz = SZ(fac);
for(ll mask = 1 ; mask < (1LL<<sz); mask++){ //容斥过程,复杂度2^因数个数
ll c = 0;
ll tmp = 1;
rep(i,sz) if( (1LL<<i)&mask){
c++;
tmp *= fac[i];
}
if(c&1) ans += MAXN/tmp;
else ans -= MAXN/tmp;
}
return ans;
}
int main(){
while(cin>>a>>n){
ll ans = 0;
if(a&1) ans += (n+1)/2, n /= 2;
ans += no_coprime(a,n);
printf("%lld\n",ans);
}
}