約數 求反素數bzoj1053 bzoj1257
阿新 • • 發佈:2019-01-07
//約數 /* 求n的正約數集合:試除法 複雜度:O(sqrt(n)) 原理:掃描[1,sqrt(N)],嘗試d能否整除n,若能,則N/d也能 */ int factor[1600],m=0; for(int i=1;i*i<=n;i++){ if(n%i==0){ factor[++m]=i; if(i!=n/i) factor[++m]=n/i; } } /* 求[1,n]每個數的正約數集合:倍數法 複雜度:O(nlogn) 原理:對於每個數d,[1,n]中以d為約數的數就是d的倍數 */ vector<int> factor[500010];for(int i=1;i<=n;i++) for(int j=1;i*j<=n;j++) factor[i*j].push_back(i); /*兩個推論 1.一個整數的約數個數上界 為2*sqrt(n) 2.[1,n]每個數的約數個數總和大約為nlogn */
/* 題意有點繞 每個人手裡有一個非0數字,首先第k個人出列,然後按其手裡的數字讓下一個人出列 迴圈如此,設i為小於等於N的最大反素數,問第i個出列的人的編號 打表求反素數:按質因數大小遞增順序搜尋每一個質因子,列舉每一個質因子的個數 唯一分解定理,一個數的因子數:(p1+1)(p2+1)(p3+1)... 性質1:一個反素數的質因子必然是從2開始連續的質數 性質2: 1 2 3 4 6 9 12 18 36*/ #include<cstdio> #include<algorithm> #include<cstring> using namespace std; #define ll long long #define inf 1<<29 int n,p[]={0,2,3,5,7,11,13,17,19,23,29,31},use[20]; ll maxt,ans;//maxt是最大因子數,ans是當前的反質數 //id是素數表的下標,now是當前數字,tot是因子數,符合因子數公式 void dfs(ll id,ll now,ll tot){ if(tot>maxt)//找到了因子數更大的數 ans=now,maxt=tot; else if(tot==maxt && now<ans)//找到因子數相同,但是數值更小的數 ans=now,maxt=tot; use[id]=0; while(now*p[id]<=n && use[id]+1<=use[id-1]){//第二個是剪枝 use[id]++; now*=p[id]; dfs(id+1,now,tot*(use[id]+1)); } } int main(){ scanf("%d",&n); use[0]=inf; dfs(1,1,1); printf("%lld",ans); return 0; }
推公式題,詳見進階指南p134
思路大概是:當i在區間[x,k/(k/x)]時,k/i的值都是一樣的,那麼這一段的值可以用等差數列求和公式做
#include<iostream> #include<cstring> #include<cstdio> using namespace std; long long n,k; long long ans; int main(){ scanf("%lld%lld",&n,&k); ans=(long long)n*k; for(int x=1,gx=0;x<=n;x=gx+1){ gx=k/x?min(n,k/(k/x)):n; ans-=(k/x)*(x+gx)*(gx-x+1)/2;//首項x*k/x,末項gx*k/x,項數gx-x+1 } printf("%lld\n",ans); }