zoukankan      html  css  js  c++  java
  • 中竞杯校赛 E.数论只会 for 循环 (数论分块 + 记忆化搜索)

    题目链接:https://ac.nowcoder.com/acm/contest/9680/E

    由定义式可以发现,如果 (k > log(n)),那么答案就一定是 (0), 所以我们只需要计算 (k <= 27) 的答案即可

    记忆化搜索,使用 (unordered_map) 存储 (dp) 数组的答案

    对于每个块,如果左端点为 (l), 那么对于 (log(i)), 右端点 (r1 = 1 << log(i)), 对于 (frac{n}{i}),右端点为 (r2 = frac{n}{frac{n}{l}})
    每次分块的右端点 (r)(r = min(r1, r2)) 即可,具体实现参考代码

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<unordered_map> 
    using namespace std;
    typedef long long ll;
    
    const int M = 1000000007;
    
    int n, k;
    
    unordered_map<int, int> dp[30];
    
    int dfs(int N, int K){
    	if(K == 0){
    		return dp[K][N] = 1;
    	}
    	if(dp[K].find(N) != dp[K].end()){
    		return dp[K][N];
    	}
    	
    	int res = 0;
    	int l, r;
    	
    	int kk = 0;
    	for(l = 2 ; l <= N ;){
    		while(1 << (kk + 1) < l) ++kk; 
    		if((1 << kk) < l) ++kk;
    		
    		r = min(min(N / (N / l), (1 << kk)), N);
    				
    		res = (res + 1ll * (r - l + 1) * kk % M * dfs(N / l, K - 1) % M) % M;
    		l = r + 1;
    	}
    	
    	return dp[K][N] = res;
    }
    
    ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
    
    int main(){
    	n = read(), k = read();
    	if(k >= 27) printf("0
    ");
    	else {
    		printf("%d
    ", dfs(n, k));
    	}
    		
    	return 0;
    }
    
  • 相关阅读:
    叶问14
    叶问13
    叶问12
    叶问11
    叶问10
    叶问9
    Java三种循环之间的区别
    利用Java对象数组制作简易学生管理系统
    什么叫java方法重载?
    Java编译器的常量优化
  • 原文地址:https://www.cnblogs.com/tuchen/p/14165921.html
Copyright © 2011-2022 走看看