饿了吗笔试20250314算法题第三题,简单梳理一下自己的解法
思路:首先最外层是动态规划,cnt[k]=cnt[k-1]+m;
这里cnt[k]是k计算result,tmp是(i+k)/gcd(i,k)累加,其中i属于[1,k-1];
然后说一下怎么求tmp,tmp对于k为质数和合数有不同的求法。
如果k是质数,m的结果是(k)*(k-1)*3/2;
而如果k不是质数,先假设它是质数,然后减去一个数dif。
说一下怎么求dif,对于所有比根号k小且被k整除的质数j,有k/j=c;则合数是由质数的j*(1+2+...c-1)*(c*j)/1变成了j(1+2+...c-1)*(c*j)/j,也就是(1+2+...c-1)*(c*j),相比质数少了(j-1)(1+2+...c-1)*(c*j);所以dif就是所有比根号k小且被k整除的质数j,k/j=c,对(j-1)(1+2+...c-1)*(c*j)的累加;然后对于任意正整数n,输出cnt[n]即可;时间复杂度是nlog(n);#笔试#
c++代码如下
#include <bits/stdc++.h> using namespace std; const int M = 1000000007; const int N = 1000000; bool ip[N+10];//判断是否是质数,true表示为合数 int cnt[N+10];//动态规划的dp数组 vector<int> edge[N+10]; void before(){ //先把N以内的合数找到 for(int i=2;i<N;i++){ for(int j=i+i;j<N;j+=i){ ip[j]=true; } } //p中存储N中所有素数 vector<int> p; for(int i=2;i<N;i++){ if(!ip[i]) p.push_back(i); } //初始化dp cnt[2]=3; for(int i=3;i<N;i++){ long long tmp=0; long long dif=0; //如果是合数,求它相比于质数需要减的数dif if(ip[i]){ for(int j=0;p[j]*p[j]<=i;j++){ //找所有比根号i小的质数,可以推导以下的公式 if(i%p[j]==0){ dif+=((p[j]-1)*3/2*(i/p[j])*(i/p[j]-1))%M; } } } tmp=(3*(i)*(i-1)/2)%M; tmp=(tmp-dif+cnt[i-1])%M; cnt[i]=tmp; } } void solve(){ for(int i=2;i<100;i++){ cout<<cnt[i]<<endl; } } int main() { int t=1; // cin>>t; before(); //这里我是自己测试的代码,就没有cin输入了,如果有测试样例,可以改一下。 while(t--){ solve(); } return 0; }