function(min_25筛 分块)

original link - https://nanti.jisuanke.com/t/41390

题意:

在这里插入图片描述

解析:

∑ i = 1 n f ( i ! ) = ( n + 1 ) ∑ i = 1 n f ( i ) − ∑ i = 1 n i f ( i ) \sum_{i=1}^nf(i!)=(n+1)\sum_{i=1}^nf(i)-\sum_{i=1}^nif(i) i=1nf(i!)=(n+1)i=1nf(i)i=1nif(i)

考虑每个 p e p^e pe的贡献,前半部分中 ∑ i = 1 n f ( i ) = ∑ ⌊ n p e ⌋ \sum_{i=1}^nf(i)=\sum \lfloor\frac{n}{p^e}\rfloor i=1nf(i)=pen,例如 [ 1 , 10 ] [1,10] [1,10] 2 2 2的贡献为 5 5 5 4 4 4的贡献为 2 2 2 8 8 8的贡献为 1 1 1…\

但是我们只能枚举 p ≤ n p\leq\sqrt n pn 的质数,想办法处理 p ≥ n p\geq \sqrt n pn 的部分。 p ≥ n p\geq \sqrt n pn 的部分 e e e只能是 1 1 1,所以变为 ∑ p ≥ n ⌊ n p ⌋ \sum_{p\geq \sqrt n}\lfloor\frac{n}{p}\rfloor pn pn。方便起见,我们枚举质数时从 e = 2 e=2 e=2开始算,另外部分变为 ∑ p ∈ [ 1 , n ] ⌊ n p ⌋ \sum_{p\in[1,n]}\lfloor\frac{n}{p}\rfloor p[1,n]pn

这个式子可以分块去做,假设 p ∈ [ l , r ] p\in[l,r] p[l,r] ⌊ n p ⌋ = x \lfloor\frac{n}{p}\rfloor=x pn=x,这部分答案就是 [ l , r ] [l,r] [l,r]的质数个数乘上 x x x。怎么做区间的质数个数? m i n _ 25 min\_25 min_25筛即可。


还有就是 ∑ i = 1 n i f ( i ) \sum_{i=1}^nif(i) i=1nif(i),想一下式子为 ∑ i = 1 n i f ( i ) = ∑ ⌊ n p e ⌋ ∗ ( ⌊ n p e ⌋ + 1 ) 2 p e \sum_{i=1}^nif(i)=\sum \dfrac{\lfloor\frac{n}{p^e}\rfloor*(\lfloor\frac{n}{p^e}\rfloor+1)}{2}p^e i=1nif(i)=2pen(pen+1)pe

同样,先枚举 p ≤ n p\leq\sqrt n pn 的质数的 e > 1 e>1 e>1次方,另外部分为 ∑ p ∈ [ 1 , n ] ⌊ n p ⌋ ∗ ( ⌊ n p ⌋ + 1 ) 2 p \sum_{p\in[1,n]}\dfrac{\lfloor\frac{n}{p}\rfloor*(\lfloor\frac{n}{p}\rfloor+1)}{2}p p[1,n]2pn(pn+1)p ⌊ n p ⌋ \lfloor\frac{n}{p}\rfloor pn分块处理,剩下部分为区间内的质数之和,也是 m i n _ 25 min\_25 min_25筛。

代码:

/*
 *  Author : Jk_Chen
 *    Date : 2019-09-27-11.16.23
 */
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair<int, int>
#define fi first
#define se second
#define debug(x) cerr<<#x<<" = "<<x<<'\n';
const LL mod=998244353;
const int maxn=1e6+9;
const int inf=0x3f3f3f3f;
LL rd(){ LL ans=0; char last=' ',ch=getchar();
    while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
    while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')ans=-ans; return ans;
}
/*_________________________________________________________begin*/

LL Pow(LL a,LL b,LL mod){
    if(a>=mod)a%=mod;
    LL res=1;
    while(b>0){
        if(b&1)res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
/*_________________________________________________________Pow*/

void Add(LL &a,LL b){a=(a%mod+b%mod);while(a>mod)a-=mod; while(a<0)a+=mod;}
LL inv2=Pow(2,mod-2,mod),inv3=Pow(3,mod-2,mod);

bool vis[maxn];
LL pri[maxn],now;
LL sum[maxn];
void init(int n){// 素数筛
    rep(i,2,n){
        if(!vis[i])pri[++now]=i,sum[now]=(sum[now-1]+i)%mod;
        for(int j=1;j<=now&&1ll*pri[j]*i<=n;j++){
            vis[pri[j]*i]=1;
            if(i%pri[j]==0)break;
        }
    }
}

LL n,sqr;
LL val[maxn],idx1[maxn],idx2[maxn],ct;// 离散化

LL g0[maxn],g1[maxn];// g函数值

int main(){
    n=rd();
    sqr=sqrt(1.0*n);
    init(sqr);
        // n/i 进行分段
    for(LL l=1,r;l<=n;l=r+1){
        r=n/(n/l);
        val[++ct]=n/l;
        n/l<=sqr ? idx1[n/l]=ct : idx2[n/(n/l)]=ct;

            // 初始化g(x,0) x=val[ct]
            // f(p)=1 , 1+1+...1
        g0[ct]=val[ct]-1;
            // f(p)=i , 2+3+...val[ct]
        g1[ct]=(2+val[ct])%mod*((val[ct]-1)%mod)%mod*inv2%mod; // 注意1e10*1e10
    }
    	// 预处理 g(n/x,|P|) |P|=now
    rep(j,1,now){ //g(val[i],j)
        rep(i,1,ct){
            if(pri[j]*pri[j]>val[i])break; // g(x,j)=g(x,j-1)
            int k = // idx(val[i]/Pj)
                val[i]/pri[j]<=sqr ? idx1[val[i]/pri[j]] : idx2[n/(val[i]/pri[j])];
            Add(g0[i],-(g0[k]-(j-1)));
            Add(g1[i],-pri[j]*((g1[k]-sum[j-1])%mod)%mod);
        }
    }
    LL ans=0;
    rep(i,1,now){
        LL v=pri[i]*pri[i];
        while(v<=n){
            Add(ans,(n+1)%mod*(n/v%mod)%mod);
            Add(ans,-(n/v+1)%mod*(n/v%mod)%mod*inv2%mod*(v%mod)%mod);
            v*=pri[i];
        }
    }
    for(LL l=1,r;l<=n;l=r+1){
        r=n/(n/l);
        int R= r<=sqr?idx1[r]:idx2[n/r], L= l-1<=sqr?idx1[l-1]:idx2[n/(l-1)];
        Add(ans, (n/l)%mod*((n+1)%mod)%mod*((g0[R]-g0[L])%mod)%mod);
        Add(ans, -(n/l+1)%mod*(n/l%mod)%mod*inv2%mod*((g1[R]-g1[L])%mod)%mod);
    }
    printf("%lld\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
分块大津(Block Jaccard Index)在MATLAB中主要用于图像处理和数据分析中,特别是比较两个图像或数据集的相似度。这种方将数据或图像分割成多个小块(或称为窗口),然后计算每个小块内的交集和并集,最后根据Jaccard相似系数(也叫Jaccard指数,是交集大小除以并集大小)来评估整体的相似性。这在处理大型数据集或减小内存需求时很有用。 在MATLAB中实现分块大津的基本步骤可能包括以下几个部分: 1. **数据预处理**:首先,将输入数据(如矩阵或图像)分割成指定大小的块。 2. **计算交集和并集**:对于每个块,计算它与另一个块的交集(共享元素的数量)和并集(总元素数量)。 3. **累加得分**:对所有块的Jaccard分数求和或平均,得到整个数据集的相似度评分。 4. **可能的优化**:使用并行计算或多线程来加速计算过程,如果数据量非常大。 具体代码可能类似于这样(假设有一个`data1`和`data2`的矩阵,`blockSize`是块的大小): ```matlab function similarity = blockJaccard(data1, data2, blockSize) [rows, cols] = size(data1); numBlocks = ceil([rows cols] / blockSize); % 初始化得分矩阵 similarityMatrix = zeros(numBlocks); % 分块计算 for i = 1:numBlocks startRow = i * blockSize(1); endRow = min(startRow + blockSize(1) - 1, rows); startCol = i * blockSize(2); endCol = min(startCol + blockSize(2) - 1, cols); % 计算当前块的交集和并集 blockData1 = data1(startRow:endRow, startCol:endCol); blockData2 = data2(startRow:endRow, startCol:endCol); intersection = sum(blockData1 & blockData2); union = sum(blockData1 | blockData2); % 更新得分矩阵 similarityMatrix(i) = intersection / union; end % 计算总相似度 similarity = sum(similarityMatrix); end ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值