https://codeforces.com/gym/102767/problem/E
思路比较直接:套用大数质因数分解的板子。
然而我威海的板子T了..没错板子T了。
于是更新板子,去洛谷找了一个优化版本的。
板子源自网络。这道题用时400ms,相当优秀。
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<map>
#include<stdlib.h>
#include<time.h>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
typedef long long ll;
typedef long long LL;
ll n, Max = 0;
inline ll mul(ll a, ll b, ll mod)
{
ll d = (long double)a / mod * b + 1e-8; //还必须是long double……double精度不够
ll r = a * b - d * mod;
return r < 0 ? r + mod : r;
}
inline ll quickpow(ll a, ll b, ll mod)
{
ll ret = 1;
for(; b; b >>= 1, a = mul(a, a, mod))
if(b & 1) ret = mul(ret, a, mod);
return ret;
}
inline bool test(ll a, ll d, ll n)
{
ll t = quickpow(a, d, n);
if(t == 1) return 1;
while(d != n - 1 && t != n - 1 && t != 1) t = mul(t, t, n), d <<= 1;
return t == n - 1; //这里就不用判1了,因为只可能在while前出现1的情况
}
int a[] = {2, 3, 5, 7, 11};
inline bool miller_rabin(ll n)
{
if(n == 1) return 0;
for(int i = 0; i < 5; ++i) //先粗筛一遍
{
if(n == a[i]) return 1;
if(!(n % a[i])) return 0;
}
ll d = n - 1;
while(!(d & 1)) d >>= 1;
for(int i = 1; i <= 5; ++i) //搞五遍
{
ll a = rand() % (n - 2) + 2;//x属于[2, n - 1]
if(!test(a, d, n)) return 0;
}
return 1;
}
inline ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
inline ll f(ll x, ll a, ll mod) {return (mul(x, x, mod) + a) % mod;}
const int M = (1 << 7) - 1; //我也不知道为啥M是这个数……
ll pollard_rho(ll n) //倍增版!减少gcd调用次数。(好像不用判环?)
{
for(int i = 0; i < 5; ++i) if(n % a[i] == 0) return a[i];
ll x = rand(), y = x, t = 1, a = rand() % (n - 2) + 2;
for(int k = 2;; k <<= 1, y = x)
{
ll q = 1;
for(int i = 1; i <= k; ++i)
{
x = f(x, a, n);
q = mul(q, abs(x - y), n);
// if(i >= M) //不等价!
if(!(i & M)) //超过了2 ^ 7,再用gcd
{
t = gcd(q, n);
if(t > 1) break; //找到了
}
}
if(t > 1 || (t = gcd(q, n)) > 1) break; //之所以再求一遍,是处理刚开始k < M的情况
}
return t;
}
LL factor[100],total=0;
inline void find(ll x)
{
if(x == 1 || x <= Max) return;
if(miller_rabin(x)) {factor[++total]=x; return;}
ll p = x;
while(p == x) p = pollard_rho(x);
while(x % p == 0) x /= p;
find(p); find(x);
}
int main(){
long long x,m,i,t;
scanf("%lld",&t);
while (t--){
scanf("%lld",&x);
LL A,B,C;
scanf("%lld%lld%lld",&A,&B,&C);
if (miller_rabin(x)){
printf("%lld\n",C+x);
}
else{///X是合数
memset(factor,0,sizeof(factor));
total=0;
find(x);
sort(factor+1,factor+total+1);
LL Primemin=factor[1];///最小质因子
LL Primemax=factor[total];///最大质因子
LL sum1=A+x/Primemax;
LL sum2=0;
LL k=x/Primemin;///最大因数
if(miller_rabin(k)){
sum2=A+x/k;
}
else{
sum2=B+x/k;
}
LL sum3=C+x;
printf("%lld\n",min(sum1,min(sum2,sum3)));
}
}
return 0;
}