北京清北 綜合強化班 Day2 T1
阿新 • • 發佈:2017-10-02
tdi 沒有 class for bre 情況 數值 pla logs 對於 60%的數據, 1≤??≤1000。
對於 100%的數據, 1≤??≤10^11。
a
【問題描述】
你是能看到第一題的 friends呢。
—— hja
世界上沒有什麽比賣的這 貴彈丸三還令人絕望事了,所以便麽一道題。定義 ??(??)為滿足 (??×??)|??的有序正整數對 (??,??)的個數。現在給定 ??,求 Σ??(??)????=1
【輸入格式】
一行個整數 ??。
【輸出格式】
一行個整數代表答案 。
【樣例輸入】
6
【樣例輸出】
25
【數據範圍與規定】
對於 30%的數據, 1≤??≤100。
對於 100%的數據, 1≤??≤10^11。
思路:
1.一開始寫的O(n^3)還以為會超時,結果竟然奇跡的60???
2.正解如下:
根據題意轉化成a*b*c<=n
強行假定a<b<c,求得一個答案,然後直接乘以6.
所以1<=a<=(根下n 3次方),即可直接寫成:
for(int a=1,v; a*a<=(v=n/a); ++a,++ans) //++ans是因為會有a,a,a的情況,不會出現重復的(在下面弄的話太麻煩,所以直接特殊弄上a*a*a的情況) for(int b=a+1; b*b<=v; ++b) tmp+=n/(a*b)-b; //因為在這裏的a,b已經確定,所以可以直接把c表示出來,又因為c必須要>b,所以c是從b+1進行取的,所以最後表示的時候需要把b減去,因為如果直接+c的話會多加了b種情況,故-b ans+=tmp*6; //明顯排列問題
但是這樣做是不對的,因為a,b,c他們三個的數值不一定是不相等的,還會出現相等的情況((a,a,b)之類的),所以需要把那些相等的排列算上.
但是這裏就又會出現一個問題:
重復加該怎麽辦?
當然就是減掉啦!
減掉的方法:
for(int a=1,v; (v=a*a)<=n; ++a) {
tmp+=n/v;
if(a*a<=n/a) tmp--;
}
上代碼:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace std; const int Maxn = 1011; int n,ans,cnt; int a[Maxn],prime[Maxn],w[Maxn]; bool notprime[Maxn]; void gets() { notprime[1]=true; for(int i=2; i<=n; ++i) { if(!notprime[i]) prime[++cnt]=i; for(int j=1; j<=cnt && i*prime[j]<=n; ++j) { notprime[i*prime[j]]=true; if(i%prime[j]==0) break; } } for(int i=1; i*i<=n; ++i) w[i*i]=1; } int calc1(int x) { //只能過樣例233 int ret=0; if(a[x] && a[x]!=3) return a[x]; for(int i=2; i<x; ++i) if(x%i==0) { if(w[i]) ret--; ret+=calc1(i); } if(w[x]) ret--; return a[x]+ret; } int calc2(int x) { int ret=0; for(int i=1; i<=x; ++i) for(int j=x; j>=1; --j) { int c=i*j; if(x/c*c==x) ret++; } return ret; } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); scanf("%d",&n); gets(); for(int i=2; i<=n; ++i) a[i]=3; a[1]=1; for(int i=1; i<=n; ++i) if(notprime[i]) a[i]=calc1(i); for(int i=1; i<=n; ++i) ans+=a[i]; printf("%d",ans); return 0; }60
#include<cstdio> #include<cstdlib> #include<cstring> using namespace std; #ifdef unix #define LL "%lld" #else #define LL "%I64d" #endif //自適應評測系統 long long n; int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); scanf(LL,&n); long long ans=0,tmp=0; for (long long a=1,v; a*a<=(v=n/a); a++,ans++) for (long long b=a+1; b*b<=v; b++) tmp+=n/(a*b)-b; ans+=tmp*6; tmp=0; for (long long a=1,v; (v=a*a)<=n; a++) { tmp+=n/v; if (a*a<=n/a) tmp--; } ans+=tmp*3; printf(LL "\n",ans); return 0; }正解
北京清北 綜合強化班 Day2 T1