Mark the Rope
Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 245 Accepted Submission(s): 73
Problem Description
Eric has a long rope whose length is N, now he wants to mark on the rope with different colors. The way he marks the rope is:
1. He will choose a color that hasn’t been used
2. He will choose a length L (N>L>1) and he defines the mark’s value equals L
3. From the head of the rope, after every L length, he marks on the rope (you can assume the mark’s length is 0 )
4. When he chooses the length L in step 2, he has made sure that if he marks with this length, the last mark will be at the tail of the rope
Eric is a curious boy, he want to choose K kinds of marks. Every two of the marks’ value are coprime(gcd(l1,l2)=1). Now Eric wants to know the max K. After he chooses the max K kinds of marks, he wants to know the max sum of these K kinds of marks’ values.
You can assume that Eric always can find at least one kind of length to mark on the rope.
Input
First line: a positive number T (T<=500) representing the number of test cases
2 to T+1 lines: every line has only a positive number N (N<2
63) representing the length of rope
Output
For every test case, you only need to output K and S separated with a space
Sample Input
Sample Output
Source
2012 Multi-University Training Contest 5
这题看第一眼感觉题目好麻烦不想看,耐着性子看完发现思路比较简单,除了数据有点大以外 = =
不过这题过了很久都没人尝试,到最后好像也只有三四十个提交,过的就更少了,
我有点怀疑我的算法,但想来想去确实应该这样做,说白了就是把一个数n分解质因数,比如有a, b, c三个质因数
再比如n = a^i * b^j * c^k,于是结果就是a^i + b^j + c^k
思路很简单,但有个bug就是2^63-1这样级别的数你该打多少的素数表?事实证明就算时间够你的数组也会超,编译都通不过
这是就要用到两个函数miller_rabin, 和pollard_rho,大概就是伪随机素数的原理
具体的做法是
1)先打10^6次方级别的素数表,完了用n一个一个去除,最后剩的最大也只可能是个10^12级别左右的数,
2)再用miller_rabin判断剩下的n是不是质数,是的话直接就结了
2)如果不是的话就用pollar_rho,得它的一个质因子,很容易证明会是一个10^6级别左右的数,然后再除一次得另一个10^6级别左右的质因数,然后就完了
需要注意的特判是: 如果n光由一个质因子组成,比如n = a^i,那么ans = a^(i-1),因为题目规定能取的L < n
/******/中间的神奇函数来自c_cloud 的代码
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdlib>
using namespace std;
#define sq(x) (x)*(x)
#define LL long long
//const long long maxn = 2007483647;
const long long maxn = 4000005;
int cnt;
bool isp[maxn];
long long prime[2000000];
void init() {
for(int i = 0; i < maxn; i++) {
isp[i] = true;
}
isp[0] = isp[1] = false;
cnt = 0;
for(int i = 2; i < maxn; ++i) {
if(cnt >= 50000001){
printf("MLE");
break;
}
if(isp[i]) prime[cnt++] = (LL)(i);
for(int j = 0; j < cnt && prime[j] * i < maxn; ++j) {
isp[prime[j] * i] = false;
if (i % prime[j] == 0) // 这句break是将复杂度降到线性的关键
break;
}
}
}
/****************************************************************/
long long mult_mod(long long x, long long y, long long n)
{
long long t, T, a, b, c, d, e, f, g, h, v, ans;
T = (long long)(sqrt(double(n) + 0.5));
t = T * T - n;
a = x / T;
b = x % T;
c = y / T;
d = y % T;
e = a * c / T;
f = a * c % T;
v = ((a * d + b * c) % n + e * t) % n;
g = v / T;
h = v % T;
ans = (((f + g) * t % n + b * d) % n + h * T) % n;
while(ans < 0) ans += n;
return ans;
}
long long fun(long long m, long long n)
{
long long a, ans = 1;
rand();
a = rand();
a *= rand() % (n - 1);
a *= rand() % (n - 1);
a = a % (n - 1) + 1;
while(m)
{
if(m & 1) ans = mult_mod(ans, a, n);
m >>= 1;
a = mult_mod(a, a, n);
}
return ans;
}
long long gcd(long long a, long long b)
{
if (b == 0) return a;
else return gcd(b, a % b);
}
long long f(long long x, long long n)
{
return (mult_mod(x, x, n) + 1) % n;
}
//判断一个数是不是质数
int miller_rabin(long long n)
{
if(n == 2) return 1;
if(n < 2 || (n & 1) == 0) return 0;
long long m = n - 1, s = 0, a, i, j;
while(!(m & 1))
{
m >>= 1;
s++;
}
for(i = 1; i <= 10; i++)
{
a = fun(m, n);
if(a == 1) continue;
for(j = 1; j <= s; j++)
{
if(a == n - 1) break;
a = mult_mod(a, a, n);
}
if(j > s) return 0;
}
return 1;
}
//获得n的一个质因子,但n必须是合数
long long pollard_rho(long long n)
{
if (n < 2) return 0;
if (!(n & 1)) return 2;
long long x, y, i, d;
for(i = 1; i <= 10; i++)
{
rand();
x = rand() % n;
y = f(x, n);
d = gcd((y - x + n) % n, n);
while(d == 1)
{
x = f(x, n);
y = f(f(y, n), n);
d = gcd((y - x + n) % n, n) % n;
}
if(d) return d;
}
return 0;
}
/**************************************************/
long long n;
long long tt;
int main(){
int t;
int i;
int pp;
init();
scanf("%d", &t);
while(t --){
scanf("%I64d", &n);
long long sqn = (long long)sqrt((double)n) + 1;
int count = 0;
long long ans = 0;
for(i = 0; prime[i] <= sqn && i < maxn && prime[i]; i ++){
if(n % prime[i] == 0){
count ++;
tt = prime[i];
while(1){
if(n % (tt * prime[i]) == 0)
tt *= prime[i];
else
break;
}
n /= tt;
//printf("tt= %I64d\n",tt);
ans += tt;
pp = prime[i];
}
}
if(count == 1 && n == 1)
ans /= pp;
if(n != 1){
if(miller_rabin(n)){
if(count != 0){
ans += n;
count ++;
}
}
else{
long long xx = pollard_rho(n);
if(xx == n/xx){
ans += xx + n/xx;
count ++;
}
else{
ans += xx + n/xx;
count += 2;
}
}
}
printf("%d %I64d\n", count, ans);
}
return 0;
}