A. Bi-shoe and Phi-shoe: 给出一个数列a,对于其中的每个元素,求出欧拉函数值不小于此元素的最小数。
题解:由欧拉函数的定义可以得到,对于一个数字x,欧拉函数值不小于x的最小数是不小于x的最小素数。因此先打出素数表,再二分地对于每一个元素找出不小于它的最小素数即可。
#include<bits/stdc++.h> #define maxn 10050 #define maxm 2000050 #define INF 0x3f3f3f3f #define eps 1e-8 using namespace std; typedef long long ll; int t,n,a,p,kase=0; int pri[maxm]; bool flag[maxm]; void init(int x) { for(int i=0;i<=x;i++)flag[i]=1; flag[0]=flag[1]=0; p=0; for(int i=2;i<=x;i++) { if(flag[i]) { pri[p++]=i; for(int j=i*2;j<=x;j+=i) flag[j]=0; } } } int main() { scanf("%d",&t); init(2e6); while(t--) { scanf("%d",&n); ll ans=0; for(int i=0;i<n;i++) { scanf("%d",&a); int tmp=upper_bound(pri,pri+p,a)-pri; ans+=pri[tmp]; } printf("Case %d: %lld Xukha\n",++kase,ans); } return 0; }
C. Aladdin and the Flying Carpet: 给定两个数a和b,求b到sqrt(a)中有多少个数是a的因数。
题解:有这样一个定理:如果一个数x的唯一分解式为(p1^e1)*(p2^e2)*……*(pn^en),那么x的因数数目就是(1+e1)*(1+e2)*……*(1+en)。显然1-sqrt(x)内的因数数目就是总的因数数目除以2。然后枚举1-b减去这个区间内的因子即可。
#include<bits/stdc++.h> #define maxn 1000050 #define INF 0x3f3f3f3f #define eps 1e-8 using namespace std; typedef long long ll; int t,num=0,p,kase=0; ll a,b; int pri[maxn]; bool flag[maxn]; void init(int x) { for(int i=0;i<=x;i++)flag[i]=1; flag[0]=flag[1]=0; for(int i=2;i<=sqrt(x);i++) { if(flag[i]) { for(int j=i*i;j<=x;j+=i) flag[j]=0; } } for(int i=2;i<=x;i++) { if(flag[i]) pri[num++]=i; } } ll coun(ll x) { ll cnt=x; ll cur=0,ans=1; int i=0; if(x==0)return 0; while(i<num&&pri[i]<=sqrt(1.0*cnt)) { if(cnt%pri[i]==0) { p=0; while(cnt%pri[i]==0) { p++; cnt/=pri[i]; } ans*=(1+p); } i++; } if(cnt>1)ans*=2; return ans; } int main() { scanf("%d",&t); init(1000000); while(t--) { scanf("%lld%lld",&a,&b); ll ans; if(b>=sqrt(1.0*a))ans=0; else { ans=coun(a)/2; for(ll i=1;i<b;i++) if(a%i==0)ans--; } printf("Case %d: %lld\n",++kase,ans); } return 0; }
D. Sigma Function: 定义一个函数如下图,给定n,问1-n中有多少个数的函数值为偶数。
题解:只要某一项为偶数,整个函数值就为偶数。所以可以先讨论奇数的情况。每一项可以表示为1+pi+p2^2+……+pi^ei,只有pi与ei同时为奇数时,这项的结果才会为偶数。也就是说对于唯一分解式中的pi^ei,有pi为偶或者pi奇ei偶的情况。
pi偶ei偶与pi奇ei偶的情况中,既然指数都为偶数,那么这就一定是完全平方数。而pi偶ei奇的情况中,一个数的偶素因子只可能为2,也就是说是2的奇数次方。提出一个2来,就可以看出这个数显然是某个完全平方数的2倍。
也就是说一个数如果不是完全平方数或者完全平方数的两倍,它的函数值就为偶数。
因此答案为n-sqrt(n)-sqrt(n/2)。
E. Leading and Tailing: 给定两个数n和k,求n^k的前3位和后3位数。
题解:后3位只要在快速幂中对1000取模即可。前三位:
F. Goldbach's Conjecture: 给定一个数n,问存在多少对素数(a,b)满足a+b=n。
题解:打出素数表来,枚举小于等于n/2的每个素数,看n和它之差是不是素数即可。
G. Harmonic Number(II): 给定n,求n/i(i from 1 to n)之和。
题解:先直接处理出1-sqrt(n)的值,对于后面的值可以利用它们求出,例如值为1的有(n/1-n/2)项,值为2的有(n/2-n/3)项,直至n/i等于n/i+1。这之中n/sqrt(n)被计算了两次,需要减去。
#include<bits/stdc++.h> #define maxn 10000050 #define INF 0x3f3f3f3f #define eps 1e-8 using namespace std; typedef long long ll; const ll mod = 1000; int t,n,kase=0; int main() { scanf("%d",&t); while(t--) { scanf("%d",&n); ll ans=0; for(ll i=1;i*i<=n;i++) { ans+=(n/i)*(i-n/(n/i+1)); if(n/i!=i) ans+=i*(n/i-n/(i+1)); } printf("Case %d: %lld\n",++kase,ans); } return 0; }
H. Pairs Forming LCM: 给定正整数n,求有多少对(i,j)满足lcm(i,j)=n。
题解:对于正整数a和b,lcm(a,b)是a,b的所有素因子在其唯一分解式中较高次幂的乘积。先将n分解,对于每一项pi^ei,有两种情况:
若pi在a中的指数等于ei,那么其在b中的指数可以取0-ei,有(ei+1)种情况。若不等于ei,那么在b中的指数必为ei,a中指数可以取ei种情况。那么对于n的每个素因子都有2*ei+1种情况,将其全部相乘得到ans。考虑a和b的大小关系,除了a,b都为n的情况,都出现了两次,因此最终答案就是ans/2+1。
I. Harmonic Number: 给定n,求调和级数的前n项。
题解:这个似乎和数论没什么关系啊……?采用了分段打表的思想,每100项的结果存起来,每次只需枚举不足整百的部分即可。
#include<bits/stdc+++.h> #define maxn 1000050 #define INF 0x3f3f3f3f #define eps 1e-8 using namespace std; typedef long long ll; const ll mod = 1000; int t,n,kase=0; double ans[maxn]; void init() { double tmp=0; for(int i=1;i<=100000000;i++) { tmp+=(1.0/i); if(i%100==0) ans[i/100]=tmp; } } int main() { scanf("%d",&t); init(); while(t--) { scanf("%d",&n); double tmp=ans[n/100]; for(int i=n/100*100+1;i<=n;i++) tmp+=(1.0/i); printf("Case %d: %.10lf\n",++kase,tmp); } return 0; }
J. Mysterious Bacteria: 给定整数x,寻找一个尽可能小的数使得x为这个数的幂,求这个幂指数。
题解:将x唯一分解,则ans=gcd(e1,e2,……,ek)。有一个坑点是x可能为负,此时结果的幂指数不能为偶数。
#include<bits/stdc++.h> #define maxn 10000050 #define INF 0x3f3f3f3f #define eps 1e-8 using namespace std; typedef long long ll; const ll mod = 1000; int t,num=0,kase=0; ll n; int pri[maxn/10]; bool flag[maxn]; void init() { memset(flag,0,sizeof(flag)); flag[0]=flag[1]=1; for(int i=2;i<=sqrt(10000000);i++) { if(!flag[i]) { for(int j=i*i;j<=10000000;j+=i) flag[j]=1; } } for(int i=2;i<=10000000;i++) { if(!flag[i]) pri[num++]=i; } } int gcd(int a,int b){return b==0?a:gcd(b,a%b);} int cal(ll x) { int cur,ans=0; ll tmp=x; for(int i=0;i<num&&pri[i]*pri[i]<=tmp;i++) { if(tmp%pri[i]==0) { cur=0; while(tmp%pri[i]==0) { cur++; tmp/=pri[i]; } if(ans==0)ans=cur; else ans=gcd(ans,cur); } } if(tmp>1)ans=gcd(ans,1); return ans; } int main() { scanf("%d",&t); init(); while(t--) { scanf("%lld",&n); bool vis=0; if(n<0) { n=(-n); vis=1; } int ans=cal(n); if(vis&&ans%2==0) while(ans%2==0)ans/=2; printf("Case %d: %d\n",++kase,ans); } return 0; }
K. Large Division: 200位大数对int取模
题解:同余定理,按位取模即可。
L. Fantasy of a Summation: 给出一个长度为n的数列,选k个可重复的数字有n^k种方法,求所有方案选出的元素之和。
题解:进行了n^k次加法,每个数被选中的概率都是k/n,因此答案为sum*k*n^(k-1)。
M. Help Hanzo: 问a-b中有多少个素数。b-a<=1e5。
题解:区间素数筛法模板。
#include<bits/stdc++.h> #define maxn 100050 #define INF 0x3f3f3f3f #define eps 1e-8 using namespace std; typedef long long ll; int t,cont,kase=0; ll m,n,z,p[maxn]; bool flag[maxn],f[maxn]; void getPrime() { z=0; memset(flag,true,sizeof(flag)); for (int i=2;i<=100000;i++) { if (flag[i]) { p[z++]=i; for (int j=i*i;j<=100000;j+=i) flag[j]=0; } } } int main() { ll sz,k; getPrime(); scanf("%d",&t); while(t--) { scanf("%lld%lld",&m,&n); cont=0; if(n<70000) { for(ll i=m;i<=n;i++) if(flag[i] && i!=1)cont++; } else { if(m<=2) m=2; sz=n-m; for(ll i=0;i<=sz;i++) f[i]=true; for(i=0;i<z&&p[i]*p[i]<=n;i++) { k=m/p[i]; if(k*p[i]<m) k++; if(k<=1) ++k; while(k*p[i]<=n) { f[k*p[i]-m]=false; ++k; } } for(i=0;i<=sz;i++) if(f[i]) cont++; } printf("Case %d: %d\n",++kase,cont); } return 0; }
N. Trailing Zeros(III): 给出一个数n,问是否存在x使得x的阶乘末尾恰好有n个0。若存在求出最小的x。
题解:一个数中含有多少个5,阶乘的末尾就会含有多少个0。用二分的方法找出这个最小的点。
#include<bits/stdc++.h> #define maxn 100050 #define INF 0x3f3f3f3f #define eps 1e-8 using namespace std; typedef long long ll; int t,n,kase=0; int getnum(int x) { int ans=0; while(x) { ans+=(x/5); x/=5; } return ans; } int main() { scanf("%d",&t); while(t--) { scanf("%d",&n); int l=1,r=1000000000,ans; while(l<=r) { int mid=(l+r)/2; if(getnum(mid)>=n) { ans=mid; r=mid-1; } else l=mid+1; } printf("Case %d: ",++kase); if(getnum(ans)==n)printf("%d\n",ans); else printf("impossible\n"); } return 0; }
O. GCD-Extreme(II): 给定n,求每一对小于n的(i,j)的gcd之和。
题解:用b[n]表示1-n-1与n的gcd之和,即sum[n]=sum[n-1]+b[n]。
用a[i]表示gcd(n,x)=i的x的个数,显然b[n]=Sum(i*a[i])。所以只需求a[i]:gcd(n,x)=i,即gcd(n/i,x/i)=1。
因此只需要求出phi[i],即可知道与n/i互质的数目,这样就可以求解了。
#include<bits/stdc++.h> #define maxn 4000050 #define INF 0x3f3f3f3f #define eps 1e-8 using namespace std; typedef long long ll; int n,phi[maxn]; ll f[maxn],sum[maxn]; void init() { memset(phi,0,sizeof(phi)); phi[1]=1; for(int i=2;i<maxn;i++) { if(!phi[i]) { for(int j=i;j<maxn;j+=i) { if(!phi[j])phi[j]=j; phi[j]=phi[j]/i*(i-1); } } } memset(f,0,sizeof(f)); for(int i=1;i<maxn;i++) { for(int j=i*2;j<maxn;j+=i) f[j]+=(i*phi[j/i]); } memset(sum,0,sizeof(sum)); for(int i=2;i<maxn;i++) sum[i]=sum[i-1]+f[i]; } int main() { init(); while(scanf("%d",&n)&&n) printf("%lld\n",sum[n]); return 0; }
R. 青蛙的约会:有两只青蛙分别在长度为l的环的a,b位置,以x,y速度同向跳跃,问多长时间后可以相遇。
题解:
S. C Looooops: 对于循环for(int i=a,i!=b;i+=c),在模2^k下需要运行多少次才会跳出循环。
题解:如下图,解方程即可。
V. Maxmium GCD: 给出一个数列,求两两组合gcd的最大值。
题解:直接暴力就行,但是要注意读入的方法,可以用字符串读入。
W. Prime Time: 定义f(x)=x*x+x+41,求a-b的函数值中素数的比例。
题解:1e4的数据,预处理一下函数值的素性,然后对于每次查询维护前缀和即可。
Y. Super Powers: 输出1-2^64-1中同时是两个或两个以上数的幂的数。
题解:要想进行拆分,幂指数必须是合数。也就是幂指数只会是4-64中的合数。然后枚举底数进行判断,底数大约在1e5之内。为节省时间当幂达到2^64时就跳出循环,对于底数i最大的幂指数就是ceil(64/lgi*lg2)-1。由于存在略大于2^64的情况,此题需要使用unsigned long long。
#include<bits/ctdc++.h> #define maxn 105 #define INF 0x3f3f3f3f #define eps 1e-8 using namespace std; typedef unsigned long long ull; map<ull,int>m; map<ull,int>::iterator it; bool flag[maxn]; int p[maxn],num=0; void init() { memset(flag,0,sizeof(flag)); for(int i=2;i<=100;i++) { if(!flag[i]) { for(int j=i*2;j<=100;j+=i) flag[j]=1; } } for(int i=4;i<=100;i++) { if(flag[i]) p[num++]=i; } } ull mi(ull a,int x) { if(x==0)return 1; ull tmp=mi(a,x/2); ull ans=tmp*tmp; if(x%2==1) ans*=a; return ans; } int main() { init(); m[1]=INF; for(int i=2;i<(1<<16);i++) { double t=ceil(64.0/log(i)*log(2))-1; for(int j=0;p[j]<=t&&j<num;j++) { ull tmp=mi(i,p[j]); m[tmp]++; } } for(it=m.begin();it!=m.end();it++) cout<< it->first <<endl; return 0; }