1. 程式人生 > >北京清北 綜合強化班 Day2 T1

北京清北 綜合強化班 Day2 T1

tdi 沒有 class for bre 情況 數值 pla logs

a

【問題描述】

你是能看到第一題的 friends呢。
—— hja
世界上沒有什麽比賣的這 貴彈丸三還令人絕望事了,所以便麽一道題。定義 ??(??)為滿足 (??×??)|??的有序正整數對 (??,??)的個數。現在給定 ??,求 Σ??(??)????=1

【輸入格式】

一行個整數 ??。

【輸出格式】

一行個整數代表答案 。

【樣例輸入】

6

【樣例輸出】

25

【數據範圍與規定】

對於 30%的數據, 1≤??≤100。

對於 60%的數據, 1≤??≤1000。
對於 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