码迷,mamicode.com
首页 > 其他好文 > 详细

北京清北 综合强化班 Day2 T1

时间:2017-10-02 21:33:56      阅读:236      评论:0      收藏:0      [点我收藏+]

标签:北京   整数   lld   open   定义   方法   系统   世界   适应   

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

标签:北京   整数   lld   open   定义   方法   系统   世界   适应   

原文地址:http://www.cnblogs.com/zxqxwnngztxx/p/7622266.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!