北京清北 综合强化班 Day2 T1
Posted 云深不知处
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了北京清北 综合强化班 Day2 T1相关的知识,希望对你有一定的参考价值。
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; }
#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的主要内容,如果未能解决你的问题,请参考以下文章