1. 程式人生 > >BZOJ 3085: 反質數加強版SAPGAP

BZOJ 3085: 反質數加強版SAPGAP

3085: 反質數加強版SAPGAP

Time Limit: 3 Sec  Memory Limit: 256 MB
Submit: 496  Solved: 205
[Submit][Status][Discuss]

Description

先解釋一下SAPGAP=Super AntiPrime, Greatest AntiPrime(真不是網路流),於是你就應該知道本題是一個關於反質數(Antiprime)的問題。下面給出反質數的定義: 將一個正整數i的約數個數記為g(i),如g(1)=1,g(2)=2,g(6)=4。 如果對於一個正整數k,對於任意正整數i<k,均有g(k)>g(i),則k被稱為反質數。 比如說1,2,4,6,12就是前5個反質數。 現在給定一個N,求N以內最大的反質數。 你一定會認為這道題很簡單,你曾經做過好多遍(它就是許許多多競賽的原題呀),但是這次真的不一樣。  

Input

一個正整數N(1≤N≤10 100)。  

Output

一個正整數,表示不超過N的最大的反質數。  

Sample Input

1000

Sample Output

840

HINT

 

 

HINT

對於5%的測試資料,n≤10000。

對於10%的測試資料,n≤100000。

對於20%的測試資料,n≤109。

對於35%的測試資料,n≤1017。

對於60%的測試資料,n≤1030。

對於100%的測試資料,n≤10100。

題解:這一題和BZOJ1053相似,只是資料加強了很多,所以不能像上一題那樣暴力搜尋了。需要加上剪紙優化,假設前m個質素為:p1,p2,p3.....pm,他們的指數為:q1,q2,q3.....qm;

窩萌假設K為最小的滿足2^K>pi;

則2^(K-1)<pi;可以得到:2^q1*pi^qi>2^(q1+K-1)*pi^(qi-1)

如果要想qi為pi的指數,則必須滿足:(q1+1)(qi+1)>(q1+K)qi;(如果不滿足,則qi-1比qi更優)

則可以得到:qi<(q1+1)/(K-1);

以上對qi(i>=2)的限制;同理我們也可以對q1限制;

我們找一個不可能出現在質因子當中的質素pm;

設K為2^k>pm的最小整數;則得到不等式:2^q1>2(q1-k)*pm;

如果使得q1為2的指數,那麼必有:q1>2(q1-k+1)  -->q1<2k-1;

pm怎麼取呢? q1q2q3....qm>N的最小的qm即可;

參考程式碼:

/**************************************************************
    Problem: 3085
    User: SongHL
    Language: C++
    Result: Accepted
    Time:2296 ms
    Memory:1292 kb
****************************************************************/
 
#include<bits/stdc++.h>
using namespace std;
#define clr(a,b) memset(a,b,sizeof a) 
typedef long long ll;
struct bignum{
    static const int mo=10000;
    int a[27];
    bignum(){}
    bignum(char *s){
        memset(a,0,sizeof(a));
        int l=strlen(s),cur=0,i;
        for (i=l-1;i-3>=0;i-=4)
            a[cur++]=(s[i-3]-48)*1000+(s[i-2]-48)*100+(s[i-1]-48)*10+s[i]-48;
        for (int j=0;j<=i;j++) a[cur]=a[cur]*10+s[j]-48;
    }
    bignum(int x){
        memset(a,0,sizeof(a));
        a[0]=x;
    }
    inline void operator *= (int x){
        for (int i=0;i<27;i++) a[i]*=x;
        for (int i=0;i<26;i++){
            a[i+1]+=a[i]/mo;
            a[i]%=mo;
        }
    }
    inline bool operator == (bignum x){
        for (int i=0;i<27;i++)
            if (a[i]!=x.a[i]) return 0;
        return 1;
    }
    inline bool operator < (bignum x){
        for (int i=26;i>=0;i--)
            if (a[i]!=x.a[i]) return a[i]<x.a[i];
        return 0;
    }
    void print(){
        int cnt=26;
        for (;!a[cnt]&&cnt;cnt--);
        printf("%d",a[cnt]);
        for (cnt--;cnt>=0;cnt--) printf("%04d",a[cnt]);
        printf("\n");
    }
}n,ans,tmp;
char s[105];
int pri[]={1,  2,  3,  5,  7,  11, 13, 17, 19, 23,
            29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
            71, 73, 79, 83, 89, 97, 101,103,107,109,
            113,127,131,137,139,149,151,157,163,167,
            173,179,181,191,193,197,199,211,223,227,
            229,233,239,241,251};
int bin[]={
    1,2,2,3,3,4,4,5,5,5,
    5,5,6,6,6,6,6,6,6,7,
    7,7,7,7,7,7,7,7,7,7,
    7,7,8,8,8,8,8,8,8,8,
    8,8,8,8,8,8,8,8,8,8,
    8,8,8,8,8};
ll q1,m,mx;
void dfs(int k,bignum now,ll cnt,ll la)
{
    if(cnt>mx||cnt==mx&&now<ans)  ans=now,mx=cnt;
    if(k!=1) la=min(la,q1/(bin[k]-1));
    ll tmp=cnt;
    for(int i=1;i<=la;i++)
    {
        if(k==1) q1=i;
        tmp+=cnt;
        now*=pri[k];
        if(n<now) break;
        dfs(k+1,now,tmp,i);
    }
}
int main()
{
    scanf("%s",s);
    n=bignum(s);
    tmp=bignum(1);
    if (n==tmp)
    {
        printf("1");
        return 0;
    }
    for (;tmp<n||tmp==n;) tmp*=pri[++m];
    dfs(1,bignum(1),1,2*bin[m]-2);
    ans.print();
    return 0;
}