zoukankan      html  css  js  c++  java
  • 【11.27】做题日记

    杜教筛模板

    又写了一遍,发现之前写的有错误,竟然水过去了,我线筛今天写错了两遍,我以后再写错我是傻逼。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = 3e6 + 10;
    typedef long long ll;
    
    ll prime[N], cnt, mu[N], phi[N], sm[N], sp[N];
    bool vis[N];
    
    void init() {
    	mu[1] = phi[1] = 1;
    	for (int i = 2; i < N; i++) {
    		if (!vis[i])prime[++cnt] = i, mu[i] = -1, phi[i] = i - 1;
    		for (int j = 1; j <= cnt and prime[j] * i < N; j++) {
    			vis[prime[j] * i] = 1;
    			mu[prime[j] * i] = -mu[i];
    			phi[prime[j] * i] = (prime[j] - 1) * phi[i];
    			if (i % prime[j] == 0) {
    				mu[prime[j] * i] = 0;
    				phi[prime[j] * i] = phi[i] * prime[j];
    				break;
    			}
    		}
    	}
    	for (int i = 1; i < N; i++) sm[i] = sm[i - 1] + mu[i], sp[i] = sp[i - 1] + phi[i];
    }
    
    unordered_map<ll, ll>M, P;
    ll m(ll n) {
    	if (n < N)return sm[n];
    	if (M.count(n)) return M[n];
    	ll ans = 1;
    	for (ll l = 2, r; l <= n; l = r + 1) {
    		r = n / (n / l);
    		ans -= (r - l + 1) * m(n / l);
    	}
    	return M[n] = ans;
    }
    
    ll p(ll n) {
    	if (n < N)return sp[n];
    	if (P.count(n)) return P[n];
    	ll ans = n * (n + 1) / 2;
    	for (ll l = 2, r; l <= n; l = r + 1) {
    		r = n / (n / l);
    		ans -= (r - l + 1) * p(n / l);
    	}
    	return P[n] = ans;
    }
    
    ll T, n;
    int main() {
    	init();
    	scanf("%lld", &T);
    	while (T--) {
    		scanf("%lld", &n);
    		printf("%lld %lld
    ", p(n), m(n));
    	}
    }
    

    P1390 公约数的和 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

    [sum_{i=1}^nsum_{j = i + 1}^ngcd(i,j) ]

    求解:

    我们求 (t = sum_{i=1}^nsum_{j=1}^ngcd(i,j)=2sum_{i=1}^nsum_{j = i + 1}^ngcd(i,j) + sum_{i=1}^n)

    [sum_{i=1}^nsum_{j=1}^ngcd(i,j)=sum_{i=1}^nsum_{j=1}^nsum_{d|gcd(i,j)}varphi(d)\=sum_{d=1}^nvarphi(d) lfloor dfrac ni floorlfloor dfrac ni floor ]

    直接 (O(n)) 求就可以了,不需要分块,因为预处理就需要 (O(n)) 的时间差不了多少

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int N = 2e6 + 10;
    ll phi[N], prime[N], cnt, vis[N];
    ll sum[N];
    void init(){
    	phi[1] = 1;
    	for(int i = 2; i < N;i++){
    		if (!vis[i])prime[++cnt] = i, phi[i] = i - 1;
    		for(int j = 1; j <= cnt and prime[j] * i < N;j++){
    			
    			phi[prime[j] * i] = phi[i] * (prime[j] - 1);
    			vis[prime[j] * i] = 1;
    			if(i % prime[j] == 0){
    				phi[prime[j] * i] = phi[i] * prime[j];
    				break;
    			}
    		}
    	}
    	for (int i = 1;i < N;i++)sum[i] = sum[i - 1] + phi[i];
    }
    int main(){
    	init();
    	int n;scanf("%d", &n);
    	long long ans = 0;
    	for(int i = 1;i <= n;i++){
    		ans -= i;
    		ans += phi[i] * (n / i) * (n / i);
    	}
    	ans >>= 1;
    	printf("%lld
    ", ans);
    }
    

    还偷来了一个别人的筛素数的东西,但是跑的在 51nod 上跑的好像根 min25 差不了多少

    #6235. 区间素数个数 - 题目 - LibreOJ (loj.ac)

    P3912 素数个数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

    min25

    #include <bits/stdc++.h>
    #define int long long
    using namespace std;
    
    const int maxn = 1e6 + 10;
    int prime[maxn], cnt, vis[maxn];
    int g[maxn], tot, w[maxn], idx1[maxn], idx2[maxn];
    int sqr, n;
    
    
    signed main() {
        cin >> n;
        sqr = sqrt(n + 0.5);
    
        for (int i = 2; i <= sqr; i++) {
            if (!vis[i]) {
                prime[++cnt] = i;
            }
    
            for (int j = 1; j <= cnt && prime[j] * i <= sqr; j++) {
                vis[prime[j]*i] = 1;
    
                if (!i % prime[j])
                    break;
            }
        }
    
        for (int l = 1, r; l <= n; l = r + 1) {
            r = n / (n / l);
            w[++tot] = n / l;
            g[tot] = w[tot] - 1;
    
            if (w[tot] <= sqr)
                idx1[w[tot]] = tot;
            else
                idx2[n / w[tot]] = tot;
        }
    
        for (int i = 1; i <= cnt; i++) {
            for (int j = 1; j <= tot && prime[i] * prime[i] <= w[j]; j++) {
                int k = (w[j] / prime[i] <= sqr) ? idx1[w[j] / prime[i]] : idx2[n / (w[j] / prime[i])];
                g[j] = g[j] - (g[k] - i + 1);
            }
        }
    
        cout << g[1] << endl;
    }
    

    别人的

    暂时没懂

    /*
     * @Author: zhl
     * @LastEditTime: 2020-11-27 10:24:11
     */
    
    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    
    using ll = long long;
    int count(ll N) {
      int v = sqrt(N);
      vector<int> smalls(v + 1), larges(v + 1);
      for (int i = 1; i <= v; ++i) smalls[i] = i - 1;
      for (int i = 1; i <= v; ++i) larges[i] = N / i - 1;
      for (int p = 2; p <= v; ++p) if (smalls[p] > smalls[p - 1]) {
        int q = p * p, c = smalls[p - 1], e = min(v, N / q);
        for (int i = 1; i <= e; ++i) {
          larges[i] -= ((i * p <= v) ? larges[i * p] : smalls[N / (i * p)]) - c;
        }
        for (int i = v; i >= q; --i) smalls[i] -= smalls[i / p] - c;
      }
      return larges[1];
    }
    
    signed main(){
        ll n;
        cin >> n;
        cout << count(n) << endl;
    }
    

    image-20201127220802511

    下面的是min25

    这个代码是真的牛皮

    偷过来的跑了第一

    #include <cstdio>
    #include <cassert>
    #include <cmath>
    #include <vector>
    //Min_25
    using namespace std;
    
    using i64 = long long;
    
    int isqrt(i64 n) {
      return sqrtl(n);
    }
    
    i64 prime_pi(const i64 N) {
      if (N <= 1) return 0;
      if (N == 2) return 1;
      const int v = isqrt(N);
      int s = (v + 1) / 2;
      vector<int> smalls(s); for (int i = 1; i < s; ++i) smalls[i] = i;
      vector<int> roughs(s); for (int i = 0; i < s; ++i) roughs[i] = 2 * i + 1;
      vector<i64> larges(s); for (int i = 0; i < s; ++i) larges[i] = (N / (2 * i + 1) - 1) / 2;
      vector<bool> skip(v + 1);
      const auto divide = [] (i64 n, i64 d) -> int { return double(n) / d; };
      const auto half = [] (int n) -> int { return (n - 1) >> 1; };
      int pc = 0;
      for (int p = 3; p <= v; p += 2) if (!skip[p]) {
        int q = p * p;
        if (i64(q) * q > N) break;
        skip[p] = true;
        for (int i = q; i <= v; i += 2 * p) skip[i] = true;
        int ns = 0;
        for (int k = 0; k < s; ++k) {
          int i = roughs[k];
          if (skip[i]) continue;
          i64 d = i64(i) * p;
          larges[ns] = larges[k] - (d <= v ? larges[smalls[d >> 1] - pc] : smalls[half(divide(N, d))]) + pc;
          roughs[ns++] = i;
        }
        s = ns;
        for (int i = half(v), j = ((v / p) - 1) | 1; j >= p; j -= 2) {
          int c = smalls[j >> 1] - pc;
          for (int e = (j * p) >> 1; i >= e; --i) smalls[i] -= c;
        }
        ++pc;
      }
      larges[0] += i64(s + 2 * (pc - 1)) * (s - 1) / 2;
      for (int k = 1; k < s; ++k) larges[0] -= larges[k];
      for (int l = 1; l < s; ++l) {
        int q = roughs[l];
        i64 M = N / q;
        int e = smalls[half(M / q)] - pc;
        if (e < l + 1) break;
        i64 t = 0;
        for (int k = l + 1; k <= e; ++k) t += smalls[half(divide(M, roughs[k]))];
        larges[0] += t - i64(e - l) * (pc + l - 1);
      }
      return larges[0] + 1;
    }
    
    int main() {
      i64 N;
      while (~scanf("%lld", &N)) {
        printf("%lld
    ", prime_pi(N));
      }
    }
    
  • 相关阅读:
    快捷键 Msg消息
    类 多态(迟绑定)
    DLL发布 matlab代码发布
    获取ini内容 GetPrivateProfileString GetPrivateProfileInt
    路径操作 getModuleFileName() 等
    事件高级
    JS事件基础
    运动框架
    运动小宗
    workman安装使用
  • 原文地址:https://www.cnblogs.com/sduwh/p/14050629.html
Copyright © 2011-2022 走看看