奇怪的数论

不想写博客,但是感觉自己又不是很会,只能写上便于自己以后应用了

P2261余数求和 数论分块

数论分块的应用:求解关于\(\left\lfloor\dfrac{n}{i}\right\rfloor\)的求和问题。

对于任意一个\(i\)\((i\leqslant n)\),我们需要找到一个最大的\(j\)\((i\leqslant j\leqslant n)\)使得 \(\left\lfloor\frac{n}{i}\right\rfloor\) =\(\left\lfloor\frac{n}{j}\right\rfloor\),此时\(j\)=\(\left\lfloor\frac{n}{\left\lfloor\frac{n}{i}\right\rfloor}\right\rfloor\).
此时我们发现在一段区间内\(\left\lfloor\frac{n}{i}\right\rfloor\),的值是相同的,所以我们用这一段的长度\(\times\)这一段的值,分块求解。

int ans=0;
for(int l = 1,r = 0;l <= n;l=r+1){
    r=n/(n/l);  			// 求区间的右端,这是一个数学规律 
    ans+=(r-l+1)*(n/l);
} 	

那么对于这道题而言\(\sum\limits_{i=1}^n{kmodi}\),它等价于\(\sum\limits_{i=1}^n {k-\left\lfloor\dfrac{k}{i}\right\rfloor \times i}\),再变形一下就变成了\(nk-\sum\limits_{i=1}^n {\left\lfloor\dfrac{k}{i}\right\rfloor \times i}\),这样求余数和的问题就被我们转化乘求\(\sum\limits_{i=1}^n {\left\lfloor\dfrac{k}{i}\right\rfloor} \times i\)的问题

#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
long long n,k;
long long solve(long long n,long long k){
  long long ans=n*k;
  for (long long l=1,r;l <= n;l=r+1){
    if (k/l!=0) r=min(k/(k/l),n);
    else r=n;
    ans-=(k/l)*(r-l+1)*(l+r)/2;//区间长度*区间平均值*向下取整的贡献
  }
  return ans;
}
int main(){
  scanf ("%lld%lld",&n,&k);
  long long ans=solve(n,k);
  printf("%lld\n",ans);
  return 0;
}

P3708 koishi的数学题 线性筛求约数和

虽然和第一题长的比较像,但是好像没什么关系,当然还是需要变化式子:
\(\sum\limits_{k=1}^n {\sum\limits_{i=1}^n {xmodi}}\),先看里面的公式,和上一道题完全一样的变形\(nx-\sum\limits_{i=1}^n {\left\lfloor\dfrac{x}{i}\right\rfloor \times i}\),再看外层嵌套的公式,如果我们能推出相邻两个之间的关系,那么我们就可以递推出整个式子.
\(\begin{aligned}f(x) & = n \times x-\sum\limits_{i=1}^n {\left\lfloor\dfrac{x}{i}\right\rfloor \times i }\end{aligned}\)
\(\begin{aligned}f(x+1) & = n \times (x+1) - \sum\limits_{i=1}^n {\left\lfloor\dfrac{x +1}{i}\right\rfloor \times i}\end{aligned}\)
两式相减得到:\(\begin{aligned}f(x+1)-f(x) & = n-\sum\limits_{i=1}^n {\left(\left\lfloor\dfrac{x+1}{i}\right\rfloor-\left\lfloor\dfrac{x}{i}\right\rfloor\right)}\end{aligned}\)
对于最后一个式子,明显只有当\(i|(x+1)\)的时候,\(\left\lfloor\dfrac{x+1}{i}\right\rfloor-\left\lfloor\dfrac{x}{i}\right\rfloor = 1\),否则为0
因此只有\(i\)\(x+1\)的因数时,才会对答案有贡献,所以对于做外层的\(k\)来说,答案就是\(k\)的因数和,线性筛求因数和这东西就……先背下来吧。

#include <iostream>
#include <cstdio>
#include <algorithm>
#define int long long 
using namespace std;
const int maxn=1e6+10;
int n,tot;
int g[maxn],f[maxn],primelist[maxn],dp[maxn],vis[maxn];
void init(){
  g[1]=f[1]=1;
  for (int i = 2;i <= n;i++){
    if (!vis[i]) vis[i]=1,primelist[++tot]=i,g[i]=f[i]=i+1;
    for (int j = 1;j <= tot&&i*primelist[j]<=n;j++){
      vis[primelist[j]*i]=1;
      if (i%primelist[j]==0){
	g[i*primelist[j]]=g[i]*primelist[j]+1;
	f[i*primelist[j]]=f[i]/g[i]*g[i*primelist[j]];
	break;
      }
      else{
	f[i*primelist[j]]=f[i]*f[primelist[j]];
	g[i*primelist[j]]=1+primelist[j];
      }
    }
  }
  // for (int i = 1;i <= n;i++) f[i]=f[i-1]+f[i];
}
signed main(){
  scanf ("%lld",&n);
  init();
  for (int i = 1;i <= n;i++) dp[i]=dp[i-1]+n-f[i];
  for (int i = 1;i <= n;i++) printf("%lld ",dp[i]);
  return 0;
}

P1544 蜈蚣 前缀异或和

dp外加前缀异或和,和前缀和差不多,记一下就好了

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll a[1000005],ans[1000005];
int n,m;
int main(){
  cin>>n;
  for(int i = 1; i<=n; i++) {
    scanf("%lld",&a[i]);
    ans[i] = ans[i-1] ^ a[i];
  }
  int l,r;
  while(m--) {
    scanf("%d%d",&l,&r);
    printf("%lld\n",ans[r] ^ ans[l - 1]);
  }
  return 0;
} 
posted @ 2020-10-12 16:39  小又又  阅读(87)  评论(0编辑  收藏  举报