记录一次失败的尝试
MLLMO Method求 2 ∗ n 2*\sqrt{n} 2∗n个点的时间复杂度是 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.5∗1e6。
当 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;
}