Number theory can only for loop (mathematics + block + memoization)

Topic link: click here

The main idea of ​​the topic:
Given n, kn, kn,k 计算函数:
f ( n , k ) = { 1 i f   k = 0 ∑ i = 1 n ⌈ l o g 2 i ⌉ f ( ⌊ n i ⌋ , k − 1 ) i f   k ≥ 1 f(n,k)= \begin{cases} 1 &if\ k=0\\ \sum_{i=1}^n\lceil log_2i \rceil f(\lfloor \frac ni \rfloor,k-1) &if\ k \ge 1 \end{cases} f(n,k)={ 1i=1nlog2if(in,k1)i f k =0i f k 1
The answer is 1 e 9 + 7 1e9+71e9+7 modulo

Problem analysis:
Analyzing this formula, it is obvious that f (1, k) = 0 (k ≥ 1) f(1,k)=0(k \ge 1)f(1,k)=0(k1 )
Findf (⌊ ni ⌋, k − 1) f(\lfloor \frac ni \rfloor,k-1)f(in,k1 ) medium-specific⌊ ni ⌋ \ lfloor \ frac niin is a typical block type, which can be processed in blocks, and⌊ ni ⌋ = 1 \lfloor \frac ni \rfloor=1in=1 This block size isn 2 \frac n22n, Using this property we can get f (n, k) f(n,k)f(n,k ) inf (1, x) f(1, x)f(1,x ) is approximatelylog 2 n log_2nlog2n (harmonic series)
so forn ≥ log 2 (1 e 8) ≥ 27 n \ge log_2(1e8) \ge 27nlog2(1e8)The answer to the data of 2 7 is0 00
forn ≤ log 2 (1 e 8) n \le log_2(1e8)nlog2( 1 e 8 ) we can enumerate⌈ log 2 i ⌉ \lceil log_2i \rceillog2i then use block processingf (⌊ ni ⌋, k − 1) f(\lfloor \frac ni \rfloor,k-1)f(in,k1 ) , just memorize + recursive solution

See the code for details:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<unordered_map>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
int read()
{
    
    
	int res = 0,flag = 1;
	char ch = getchar();
	while(ch<'0' || ch>'9')
	{
    
    
		if(ch == '-') flag = -1;
		ch = getchar();
	}
	while(ch>='0' && ch<='9')
	{
    
    
		res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
		ch = getchar();
	}
	return res*flag;
}
const int maxn = 5e3+5;
const int mod = 1e9+7;
const double pi = acos(-1);
const double eps = 1e-8;
unordered_map<int,int>mp[27];
int f(int n,int k)
{
    
    
	if(k >= 27) return 0;
	if(mp[k].find(n) != mp[k].end())
		return mp[k][n];
	if(k == 0) return mp[k][n] = 1;
	else {
    
    
		int& tmp = mp[k][n];
		for(int i = 1;(1<<i) <= 2*n;i++)
		{
    
    
			int l = (1<<(i-1))+1,r = min(1<<i,n),rr;
			for(int j = l;j <= r;j = rr+1)
			{
    
    
				int pos = n/j;
				rr = min(r,n/pos);
				tmp = (tmp+1ll*i*(rr-j+1)%mod*f(pos,k-1))%mod;
			}
		}
		return tmp;
	}
}
int main()
{
    
    
	int n = read(),k = read();
	printf("%d\n",f(n,k));
	return 0;
}

Guess you like

Origin blog.csdn.net/qq_39641976/article/details/110733206