整除分块+取模

整除分块,

就对n/i进行求和;

板子:

#include<bits/stdc++.h>
using namespace std;
long long n,ans;
int main()
{
  scanf("%lld",&n);
  for(int l=1,r;l<=n;l=r+1)
     {
        r=n/(n/l);
        ans+=(r-l+1)*(n/l);//块里都是相等的;
        cout<<l<<' '<<r<<' '<<ans<<endl;
     }
  printf("%lld",ans);}
取模版本:给定n和k,∑ki=1 n%i
首先 n%i=n-(n/i)*i;
然后问题就可以转化成整除分块问题(n*k-∑ki=1(n/i)*i)
,卡在了取模里 嗷嗷嗷
对每一个块来讲,等差数列求个和(r-l+1)*(l+r)/2*(n/l);
写一个取模函数即可;
代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
#include <set>
#include <map>
typedef long long ll;
const int N=100000+100;
const int mod=1e9+7;
using namespace std;
 ll a,b;
ll sum=0,ans=0;
 ll mult(ll a,ll b)
 {
     return ((a%mod)*(b%mod))%mod;
 }
 int main()
 {
     scanf("%lld %lld",&a,&b);
     sum=mult(a,b);
     b=min(a,b);
     ll l,r;
     for(ll i=1;i<=b;i=r+1)
     {
        l=i,r=a/(a/i);
        r=min(r,b);//最后一个区域的边界问题
         ll cc=0;
        if((l+r)&1) cc=mult(l+r,(r-l+1)/2);//如果为奇数
        else     cc=mult((l+r)/2,r-l+1);
         ans+=mult(cc,a/l);
         ans%=mod;
        //i=r;
     }
     sum-=ans;
    if(sum<0)   sum+=mod;
    printf("%lld\n",sum);
    return 0;}
取模时要奇数和偶数分开取模;


猜你喜欢

转载自www.cnblogs.com/sweetlittlebaby/p/12614897.html