记录一次失败的尝试(MLLMO Method单点如何优化?)

记录一次失败的尝试

MLLMO Method求 2 ∗ n 2*\sqrt{n} 2n 个点的时间复杂度是 O ( n 3 4 / l o g n ) O(n^{3\over 4}/logn) O(n43/logn)

如果我只求 n n n那一个点,考虑还使用MLLMO Method,能不能变快?

之前EES中使用的迭代方法,还是蛮巧妙的,空间复杂度 O ( n ) O(\sqrt{n}) O(n )

经过测试, d p ( n , j ) dp(n,j) dp(n,j)所有有效的状态,当 n = 1 0 10 n=10^{10} n=1010时,大概是 2.5 ∗ 1 e 6 2.5*1e6 2.51e6

n = 1 0 12 n=10^{12} n=1012,估计在 1 e 8 1e8 1e8左右,无法直接存储(甚至我不知道如何快速计算…只是hash的话常数还是比较大)

求大佬指点…

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline __int128 ff(__int128 x){return (x&1) ? (x+1)/2*x : x/2*(x+1)  ;}
ll n,M;
int tot;
const int maxn=1e6+10;
bool valid[maxn];//辅助求素数
int primes[maxn];//存1~M之间的素数
ll p2[maxn];//存1~M之间的素数 共tot个
ll pre[maxn];//存1~M之间的素数的前缀和
vector<int> preid,houid;//求满足x > P_j^2 -1 的最后的j

void getprime(int n,int &tot,int ans[])
{
    tot=0;
    memset(valid,true,sizeof(valid));
    for(int i=2;i<=n;++i){
        if(valid[i]){
            tot++;
            ans[tot]=i;
        }
        for(int j=1;(j<=tot) && (i*ans[j]<=n);++j){
            valid[i*ans[j]]=false;
            if(i%ans[j]==0) break;
        }
    }
    for(int i=1;i<=tot;++i){
        pre[i] = pre[i-1] + ans[i];
        p2[i] = 1LL*ans[i]*ans[i];
    }
    p2[tot+1] = 1e18;
    assert(p2[0] == 0);
}
void init()
{
    assert(n>=1);
    M = sqrt(n);
    assert(M<=n/M);
    getprime(M,tot,primes);
    //求满足x > P_j^2 -1 的最后的j
    preid.resize(M+1);
    houid.resize(M+1);
    if(M==1){//n<4
        preid[1] = 0;
        houid[1] = 0;
        return ;
    }
    //时间复杂度O(M)
    int j=1,i=1;
    while(i<p2[1]) i++;
    while(j<=tot && i<=M){
        if(i>=p2[j] && i<p2[j+1]){
            preid[i] = j;
            i++;
        }
        else j++;
    }
    i=M;//i
    while(n/i<p2[j]){
        i--;
    }
    assert(n/i>=p2[j]);
    while(j<=tot && i>=1){
        if(n/i>=p2[j] && n/i<p2[j+1]){
            houid[i] = j;
            i--;
        }
        else j++;
    }
//    for(int i=1;i<=M;++i) cout<<i<<": "<<preid[i]<<endl;
//    cout<<endl;
//    for(int i=M;i>=1;--i) cout<<n/i<<": "<<houid[i]<<endl;
}
unordered_map<ll,__int128> mp_pre;
unordered_map<ll,__int128> mp_hou;
__int128 solve(ll nown, int j)//不加记忆化1e11会爆栈
{
    if(p2[j]>nown) j = (nown<=M ) ? preid[nown] : houid[n/nown];
    if(j==0) return ff(nown)-1;
    if(nown<=M){
        if(mp_pre.count(nown*(M+1)+j)) return mp_pre[nown*(M+1)+j];
        else return mp_pre[nown*(M+1)+j] = solve(nown,j-1) - primes[j]*(solve(nown/primes[j], j-1) - pre[j-1]);
    }
    else{
        if(mp_hou.count(n/nown*(M+1)+j)) return mp_hou[n/nown*(M+1)+j];
        else return mp_hou[n/nown*(M+1)+j] = solve(nown,j-1) - primes[j]*(solve(nown/primes[j], j-1) - pre[j-1]);
    }
//    if(nown<=M){
//        if(!(j&1)){
//            if(mp_pre.count(nown*(M+1)+j)) return mp_pre[nown*(M+1)+j];
//            else return mp_pre[nown*(M+1)+j] = solve(nown,j-1) - primes[j]*(solve(nown/primes[j], j-1) - pre[j-1]);
//        }
//        else ;
//    }
//    else{
//        if(!(j&1)){
//            if(mp_hou.count(n/nown*(M+1)+j)) return mp_hou[n/nown*(M+1)+j];
//            else return mp_hou[n/nown*(M+1)+j] = solve(nown,j-1) - primes[j]*(solve(nown/primes[j], j-1) - pre[j-1]);
//        }
//        else ;
//    }
}
int main()
{
    n=1e10;//状态数250 0000  而  ees中是 1569 0000
    init();
    cout<<(ll)solve(n, tot)<<endl;
    cout<<"状态数为: "<<mp_hou.size()+mp_pre.size()<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值