ID
Origin
Title
  111 / 423 Problem A LightOJ 1370 Bi-shoe and Phi-shoe
  21 / 74 Problem B LightOJ 1356 Prime Independence
  61 / 332 Problem C LightOJ 1341 Aladdin and the Flying Carpet
  54 / 82 Problem D LightOJ 1336 Sigma Function
  66 / 181 Problem E LightOJ 1282 Leading and Trailing
  65 / 216 Problem F LightOJ 1259 Goldbach`s Conjecture
  65 / 110 Problem G LightOJ 1245 Harmonic Number (II)
  48 / 172 Problem H LightOJ 1236 Pairs Forming LCM
  43 / 73 Problem I LightOJ 1234 Harmonic Number
  38 / 160 Problem J LightOJ 1220 Mysterious Bacteria
  46 / 98 Problem K LightOJ 1214 Large Division
  35 / 62 Problem L LightOJ 1213 Fantasy of a Summation
  41 / 137 Problem M LightOJ 1197 Help Hanzo
  45 / 100 Problem N LightOJ 1138 Trailing Zeroes (III)
  37 / 48 Problem O UVA 11426 GCD - Extreme (II)
  13 / 65 Problem P UVA 11754 Code Feat
  9 / 26 Problem Q UVA 11916 Emoogle Grid
  36 / 86 Problem R POJ 1061 青蛙的约会
  24 / 63 Problem S POJ 2115 C Looooops
  13 / 35 Problem T POJ 2116 Death to Binary?
  61 / 122 Problem U HDU 2161 Primes
  32 / 87 Problem V UVA 11827 Maximum GCD
  25 / 98 Problem W UVA 10200 Prime Time
  20 / 154 Problem X SGU 106 The equation
  34 / 51 Problem Y POJ 2478 Farey Sequence
  23 / 63 Problem Z UVA 11752 The Super Powers
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

111 / 423 Problem A LightOJ 1370 Bi-shoe and Phi-shoe

d.给出n个数a1,a2,...,an,对每个数ai分别找到一个相应的数pi,使其欧拉函数值Φ(pi)>=ai,求p1+p2+...+pn的最小值。

s.不知道为什么pi要选大于ai的第一个素数。

  1. #include<iostream>
  2. #include<stdio.h>
  3. #include<string.h>
  4. #include<math.h>
  5. using namespace std;
  6.  
  7. const int MAXN=;
  8.  
  9. bool isPrime[MAXN];
  10.  
  11. void sieve(int n){
  12. memset(isPrime,true,sizeof(isPrime));
  13. isPrime[]=isPrime[]=false;
  14. int i,j,k;
  15. k=sqrt(n);
  16. for(i=;i<=k;++i){
  17. if(isPrime[i]==true){
  18. for(j=i+i;j<=n;j=j+i){
  19. isPrime[j]=false;
  20. }
  21. }
  22. }
  23. }
  24.  
  25. int main(){
  26.  
  27. sieve(MAXN-);
  28.  
  29. int T;
  30. int n;
  31. int t;
  32. int i;
  33. int j;
  34. long long sum;
  35. int ca=;
  36.  
  37. scanf("%d",&T);
  38.  
  39. while(T--){
  40. scanf("%d",&n);
  41. sum=;
  42. for(i=;i<n;++i){
  43. scanf("%d",&t);
  44. for(j=t+;j<MAXN;++j){
  45. if(isPrime[j]==true){
  46. break;
  47. }
  48. }
  49. sum+=j;
  50. }
  51. printf("Case %d: %lld Xukha\n",++ca,sum);
  52. }
  53.  
  54. return ;
  55. }

21 / 74 Problem B LightOJ 1356 Prime Independence

题意:
找出一些数字的最大质独立集,就是集合能的所有数互相之间不会出现 a[i]==t*a[j] (t是质数) 的情况。
思路:
首先想最大独立集对于一般图是NP问题,通常只有求二分图最大独立集,然后就是如何把这些数字分为二分图。
能够想到如果一个数字等于另一个数字乘以一个质数,那么这两个数字的质因子分解应该只有这一个质数的差别。也就是只会多一个质数,数字上限只有500000,完全可以看一个数组储存某个数字是否存在,然后对每个数字分解质因子,找到他对于每个质因子能够找到的那个数,存在则加边,然后就把质因子总个数(可重复的)是奇数与偶数的分成两边并且把只有一个质因子差别的连通,然后二分图匹配求最大独立集即可。

即二分图左边为质因子总数为奇数的,右边为质因子总数偶数的。
关于二分图匹配因为数量较大所以用匈牙利会tle,要用Hopcroft-Carp:

c.根据这个思路写了下,用的匈牙利O(VE),没超时。不过Hopcroft-Carp这个会快1s左右。

  1. /*
  2. //顶点编号从1开始的
  3. 用STL中的vector建立邻接表实现匈牙利算法
  4. 效率比较高
  5. 处理点比较多的效率很高。1500的点都没有问题
  6. */
  7. #include<iostream>
  8. #include<stdio.h>
  9. #include<algorithm>
  10. #include<string.h>
  11. #include<vector>
  12. #include<math.h>
  13. using namespace std;
  14.  
  15. const int MAXN=+;//这个值要超过两边个数的较大者,因为有linker
  16. int linker[MAXN];
  17. bool used[MAXN];
  18. vector<int>G[MAXN];
  19. int uN;
  20. bool dfs(int u)
  21. {
  22. int sz=G[u].size();
  23. for(int i=; i<sz; i++)
  24. {
  25. if(!used[G[u][i]])
  26. {
  27. used[G[u][i]]=true;
  28. if(linker[G[u][i]]==-||dfs(linker[G[u][i]]))
  29. {
  30. linker[G[u][i]]=u;
  31. return true;
  32. }
  33. }
  34. }
  35. return false;
  36. }
  37.  
  38. int hungary()
  39. {
  40. int u;
  41. int res=;
  42. memset(linker,-,sizeof(linker));
  43. for(u=; u<uN; u++)
  44. {
  45. memset(used,false,sizeof(used));
  46. if(dfs(u)) res++;
  47. }
  48. return res;
  49. }
  50.  
  51. const int MAXN2=+;
  52.  
  53. bool exist[MAXN2];//标记数是否存在
  54. int a[MAXN];//原来的数
  55. int myHash[MAXN2];//离散化
  56.  
  57. int factors[MAXN2][];//[0]存质因子,[1]存个数
  58. int factCnt;//不同的质因子总个数
  59. int factCnt2;//包含相同的质因子的总个数
  60.  
  61. void getFactors(int n){
  62. int i,k;
  63. factCnt=;
  64. factCnt2=;
  65. for(i=,k=sqrt(n);i<=k;++i){
  66. if(n%i==){
  67. factors[factCnt][]=i;
  68. factors[factCnt][]=;
  69. ++factCnt2;
  70. n=n/i;
  71. while(n%i==){
  72. ++factors[factCnt][];
  73. ++factCnt2;
  74. n=n/i;
  75. }
  76. ++factCnt;
  77. k=sqrt(n);//循环条件不直接写i<=sqrt(n);是因为这样可以避免重复开跟方
  78. }
  79. }
  80. if(n>){
  81. factors[factCnt][]=n;
  82. factors[factCnt][]=;
  83. ++factCnt;
  84. ++factCnt2;
  85. }
  86. }
  87.  
  88. int main(){
  89. int T;
  90. int N;
  91. int i;
  92. int j;
  93. int tmp;
  94. int ans;
  95. int ca=;
  96.  
  97. scanf("%d",&T);
  98.  
  99. while(T--){
  100. scanf("%d",&N);
  101. uN=N;//左边集合个数
  102. for(i=;i<uN;++i){//记得要清空
  103. G[i].clear();
  104. }
  105.  
  106. memset(exist,false,sizeof(exist));
  107. for(i=;i<N;++i){
  108. scanf("%d",&a[i]);
  109. exist[a[i]]=true;
  110. myHash[a[i]]=i;//离散化,二分图N个点就可以了
  111. }
  112.  
  113. for(i=;i<N;++i){
  114. getFactors(a[i]);//获取质因子
  115. for(j=;j<factCnt;++j){//枚举质因子
  116. tmp=a[i]/factors[j][];
  117. if(exist[tmp]==true){//tmp存在
  118. if(factCnt2&){//第i个数质因数个数为奇数,第i个数作为左边的点插入一条由左指向右的有向边
  119. G[i].push_back(myHash[tmp]);
  120. }
  121. else{
  122. G[myHash[tmp]].push_back(i);
  123. }
  124. }
  125. }
  126. }
  127. ans=hungary();
  128. printf("Case %d: %d\n",++ca,N-ans);
  129. }
  130.  
  131. return ;
  132. }

c2.Hopcroft-Carp,这个比较快,O(squt(n)*E)

  1. /*
  2. //顶点编号从0开始的
  3. 二分图匹配(Hopcroft-Karp算法)
  4. 复杂度O(squt(n)*E)
  5. 邻接表存图,vector实现
  6. vector先初始化,然后加入边
  7. uN为左端的顶点数,使用前赋值(点编号0开始)
  8. */
  9. #include<iostream>
  10. #include<stdio.h>
  11. #include<vector>
  12. #include<queue>
  13. #include<string.h>
  14. #include<math.h>
  15. using namespace std;
  16.  
  17. const int MAXN=+;
  18. const int INF=0x3f3f3f3f;
  19. vector<int>G[MAXN];
  20. int uN;
  21. int Mx[MAXN],My[MAXN];
  22. int dx[MAXN],dy[MAXN];
  23. int dis;
  24. bool used[MAXN];
  25. bool SearchP(){
  26. queue<int>Q;
  27. dis=INF;
  28. memset(dx,-,sizeof(dx));
  29. memset(dy,-,sizeof(dy));
  30. for(int i=;i<uN;i++)
  31. if(Mx[i]==-){
  32. Q.push(i);
  33. dx[i]=;
  34. }
  35. while(!Q.empty()){
  36. int u=Q.front();
  37. Q.pop();
  38. if(dx[u]>dis)break;
  39. int sz=G[u].size();
  40. for(int i=;i<sz;i++){
  41. int v=G[u][i];
  42. if(dy[v]==-){
  43. dy[v]=dx[u]+;
  44. if(My[v]==-)dis=dy[v];
  45. else{
  46. dx[My[v]]=dy[v]+;
  47. Q.push(My[v]);
  48. }
  49. }
  50. }
  51. }
  52. return dis!=INF;
  53. }
  54. bool DFS(int u){
  55. int sz=G[u].size();
  56. for(int i=;i<sz;i++){
  57. int v=G[u][i];
  58. if(!used[v]&&dy[v]==dx[u]+){
  59. used[v]=true;
  60. if(My[v]!=-&&dy[v]==dis)continue;
  61. if(My[v]==-||DFS(My[v])){
  62. My[v]=u;
  63. Mx[u]=v;
  64. return true;
  65. }
  66. }
  67. }
  68. return false;
  69. }
  70. int MaxMatch(){
  71. int res=;
  72. memset(Mx,-,sizeof(Mx));
  73. memset(My,-,sizeof(My));
  74. while(SearchP()){
  75. memset(used,false,sizeof(used));
  76. for(int i=;i<uN;i++)
  77. if(Mx[i]==-&&DFS(i))
  78. res++;
  79. }
  80. return res;
  81. }
  82.  
  83. const int MAXN2=+;
  84.  
  85. bool exist[MAXN2];//标记数是否存在
  86. int a[MAXN];//原来的数
  87. int myHash[MAXN2];//离散化
  88.  
  89. int factors[MAXN2][];//[0]存质因子,[1]存个数
  90. int factCnt;//不同的质因子总个数
  91. int factCnt2;//包含相同的质因子的总个数
  92.  
  93. void getFactors(int n){
  94. int i,k;
  95. factCnt=;
  96. factCnt2=;
  97. for(i=,k=sqrt(n);i<=k;++i){
  98. if(n%i==){
  99. factors[factCnt][]=i;
  100. factors[factCnt][]=;
  101. ++factCnt2;
  102. n=n/i;
  103. while(n%i==){
  104. ++factors[factCnt][];
  105. ++factCnt2;
  106. n=n/i;
  107. }
  108. ++factCnt;
  109. k=sqrt(n);//循环条件不直接写i<=sqrt(n);是因为这样可以避免重复开跟方
  110. }
  111. }
  112. if(n>){
  113. factors[factCnt][]=n;
  114. factors[factCnt][]=;
  115. ++factCnt;
  116. ++factCnt2;
  117. }
  118. }
  119.  
  120. int main(){
  121. int T;
  122. int N;
  123. int i;
  124. int j;
  125. int tmp;
  126. int ans;
  127. int ca=;
  128.  
  129. scanf("%d",&T);
  130.  
  131. while(T--){
  132. scanf("%d",&N);
  133. uN=N;//左边集合个数
  134. for(i=;i<uN;++i){//记得要清空
  135. G[i].clear();
  136. }
  137.  
  138. memset(exist,false,sizeof(exist));
  139. for(i=;i<N;++i){
  140. scanf("%d",&a[i]);
  141. exist[a[i]]=true;
  142. myHash[a[i]]=i;//离散化,二分图N个点就可以了
  143. }
  144.  
  145. for(i=;i<N;++i){
  146. getFactors(a[i]);//获取质因子
  147. for(j=;j<factCnt;++j){//枚举质因子
  148. tmp=a[i]/factors[j][];
  149. if(exist[tmp]==true){//tmp存在
  150. if(factCnt2&){//第i个数质因数个数为奇数,第i个数作为左边的点插入一条由左指向右的有向边
  151. G[i].push_back(myHash[tmp]);
  152. }
  153. else{
  154. G[myHash[tmp]].push_back(i);
  155. }
  156. }
  157. }
  158. }
  159. ans=MaxMatch();
  160. printf("Case %d: %d\n",++ca,N-ans);
  161. }
  162.  
  163. return ;
  164. }

61 / 332 Problem C LightOJ 1341 Aladdin and the Flying Carpet

题意:给个矩形的面积a,和矩形的最小边长b,问有多少种矩形的方案(不能是正方形)

分析:a可以写成x,y,因为不能是正方形,所以设x<y,那么x<sqrt(a),y>sqrt(a)

所以找到所有小于sqrt(a)的因子,看有几个大于等于b的就是方案数

因子可以由数的唯一分解定理,求得

具体 : 先筛一遍1e6以内的素数,有线性筛,然后分解a,然后dfs找所有的小于sqrt(a)的因子,

由于前12个素数的乘积大于1e12了,所以这部分复杂度,大概是O(2^12)(一般还要略大,不过大不了多少,数组要开大)左右

可以用这个估计(因为是求小于sqrt(a)的,可以除以2,当然这是空间常数)

所以这部分复杂度是O(T*2^12)满的话(4000*4000)大概也就是几百万,这部分可以忽略不计

主要的复杂度在分解素数里,因为1e6里面大概有7w多素数,这部分复杂度(最坏的情况a是大素数),大概是4000*70000,可以卡过,由于不可能都是这种数据

所以还是可以过的

吐槽:然后我看了看网上的代码,都是先求出总的,然后暴力扫b减,结果居然过了,b是sqrt(a)的级别,是百万,4000*1e6,是4e9,TLE

出题人太良心,没有卡这种的QAQ,感觉略坑啊

  1. #include <cstdio>
  2. #include <iostream>
  3. #include <ctime>
  4. #include <vector>
  5. #include <cmath>
  6. #include <map>
  7. #include <queue>
  8. #include <algorithm>
  9. #include <cstring>
  10. using namespace std;
  11. typedef long long LL;
  12. const int N=1e6+;
  13. const int INF=0x3f3f3f3f;
  14. int cnt;
  15. bool v[N];
  16. LL prime[];
  17. void getprime(){
  18. for(int i=;i*i<=N-;++i)
  19. if(!v[i])
  20. for(int j=i*i;j<=N-;j+=i)
  21. v[j]=;
  22. for(int i=;i<=N-;++i)
  23. if(!v[i])prime[++cnt]=i;
  24. }
  25. vector<LL>fac[];
  26. int divisors[],tot;
  27. LL k;
  28. void dfs(int pos,LL res){
  29. if(pos==fac[].size()){
  30. divisors[++tot]=res;
  31. return;
  32. }
  33. for(LL i=,now=;i<=fac[][pos];now*=fac[][pos],++i){
  34. if(now*res>=k)break;
  35. dfs(pos+,res*now);
  36. }
  37. }
  38. int main()
  39. {
  40. getprime();
  41. int cas=,T;
  42. scanf("%d",&T);
  43. while(T--){
  44. printf("Case %d: ",++cas);
  45. LL a,b;
  46. scanf("%lld%lld",&a,&b);
  47. k=sqrt(a);
  48. if(k*k!=a)++k;
  49. if(b>=k){
  50. printf("0\n");
  51. continue;
  52. }
  53. LL t=a;
  54. fac[].clear(),fac[].clear();
  55. for(int i=;i<=cnt&&prime[i]*prime[i]<=t;++i){
  56. if(t%prime[i])continue;
  57. int tmp=;
  58. fac[].push_back(prime[i]);
  59. while(t%prime[i]==)++tmp,t/=prime[i];
  60. fac[].push_back(tmp);
  61. }
  62. if(t>){
  63. fac[].push_back(t);
  64. fac[].push_back();
  65. }
  66. tot=;
  67. dfs(,);
  68. int ans=;
  69. for(int i=;i<=tot;++i)
  70. if(divisors[i]>=b)++ans;
  71. printf("%d\n",ans);
  72. }
  73. return ;
  74. }

法2:根据唯一分解定理,先将a唯一分解,则a的所有正约数的个数为num = (1 + a1) * (1 + a2) *...(1 + ai),这里的ai是素因子的指数,见唯一分解定理,因为题目说了不会存在c==d的情况,因此num要除2,去掉重复情况,然后枚举小于b的a的约数,拿num减掉就可以了

ps:这个除2很刁。如果存在c==d的情况,会给舍掉。正好符合题意不能是正方形。

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. #include <cmath>
  5. #define ll long long
  6. using namespace std;
  7. int const MAX = 1e6 + ;
  8. int p[MAX];
  9. bool u[MAX];
  10. int num, cnt;
  11. ll a, b, tmp;
  12.  
  13. void get_prime()
  14. {
  15. memset(u, false, sizeof(u));
  16. for(int i = ; i <= sqrt(MAX); i++)
  17. if(!u[i])
  18. for(int j = i * i; j <= MAX; j += i)
  19. u[j] = true;
  20. for(int i = ; i <= MAX; i++)
  21. if(!u[i])
  22. p[cnt ++] = i;
  23. }
  24.  
  25. void cal()
  26. {
  27. for(int i = ; i < cnt && p[i] <= sqrt(tmp); i++)
  28. {
  29. int cc = ;
  30. while(tmp % p[i] == )
  31. {
  32. cc ++;
  33. tmp /= p[i];
  34. }
  35. num *= (cc + );
  36.  
  37. }
  38. if(tmp > ) //如果tmp不能被整分,说明还有一个素数是它的约数,此时cc=1
  39. num *= ;
  40. }
  41.  
  42. int main()
  43. {
  44. int T;
  45. scanf("%d", &T);
  46. cnt = ;
  47. get_prime();
  48. for(int ca = ; ca <= T; ca++)
  49. {
  50. scanf("%lld %lld", &a, &b);
  51. if(a < b * b)
  52. printf("Case %d: 0\n", ca);
  53. else
  54. {
  55. num = ;
  56. tmp = a;
  57. cal();
  58. num /= ;
  59. for(int i = ; i < b; i++)
  60. if(a % i == )
  61. num --;
  62. printf("Case %d: %d\n", ca, num);
  63. }
  64. }
  65. }

54 / 82 Problem D LightOJ 1336 Sigma Function

题意:定义f(n)为n的约数之和。比如f(6)=1+2+3+6=12。给出n,求[1,n]中f值为偶数的数的个数。

c.这个代码,,很尴尬,看代码吧。

  1. #include<iostream>
  2. #include<stdio.h>
  3. #include<math.h>
  4. using namespace std;
  5.  
  6. int main(){
  7.  
  8. int T;
  9. long long n;
  10. int a,b;
  11. int ca=;
  12.  
  13. scanf("%d",&T);
  14.  
  15. while(T--){
  16. scanf("%lld",&n);
  17. a=sqrt(n);
  18. b=sqrt(n/);
  19. printf("Case %d: %lld\n",++ca,n-a-b);
  20. }
  21.  
  22. return ;
  23. }

正规点的做法:看了这个好像明白上面那个了。。。from:http://www.hardbird.net/lightoj-1336-sigma-function/

大意:定义函数σ(x)为x的所有因子的和。问题是,给一个n,问有多少个σ(x)为偶数,x<=n。

思路:可以计算有多少个σ(x)为奇数,用n减去就好了。题目中给出了提示σ(n)可以写成

其中单独的一项,是等比数列求和的公式。如果要求σ(n)为奇数,那公式中的每一项乘数都得是奇数。

对于其中的第i项乘数f(i)=pi^0+pi^1+…+pi^ei.
当pi=2时,f(i)一定是奇数。
当pi!=2时,由于pi是奇数,只有当ei为偶数时,才能保证f(i)为奇数。

所以,当所有的σ(x)为奇数时,x只有两种情况:
1、所有的ei都为偶数,x就一定是平方数。
2、除了素因子2的指数为奇数外,所有的ei都为偶数,x就一定是平方数的2倍。

  1. #include <cstdio>
  2. using namespace std;
  3. typedef long long LL;
  4.  
  5. int main()
  6. {
  7. int T, kase=;
  8. LL n;
  9. scanf("%d", &T);
  10. while(T--)
  11. {
  12. scanf("%lld", &n);
  13. LL ans=;
  14. for(LL i=; i*i<=n; i++)
  15. {
  16. ans++;
  17. if(*i*i<=n)
  18. ans++;
  19. }
  20. printf("Case %d: %lld\n", ++kase, n-ans);
  21. }
  22. return ;
  23. }

解3:

题意:求[1,n]中约数和为偶数的数的个数

思路:根据算术基本定理的约数和公式f(n)=(1+p1+p1^2+...+p1^k1)(1+p2+p2^2+...+p2^k2)...(1+pn+pn^3+...+pn^kn);

其中n=(p1^k1)*(p2^k2)*...*(pn^kn);(分解素因数)

由于奇数*奇数还是奇数,奇数*偶数或者偶数相乘是偶数。而素数除了2都是奇数。

f(n)的奇偶性取决于每个因子的奇偶性,只要出现一个因子是偶数时f(n)为偶数。

对每个因子,1+p+p^2+...+p^k的奇偶性,

p为素数,当p是2时,式子为奇数;

当p不是2时,p是奇数,p^i为奇数,式子总共k+1项,即k+1个奇数的和,k为偶数时式子为奇数。

以此条件反推dfs出所有的f(n)为奇数的n,方法是每次乘以奇素数素数的两倍或者2,得到的n就是f(n)为奇数的n了。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<cstdlib>
  5. #include<algorithm>
  6. #include<vector>
  7. #include<stack>
  8. #include<queue>
  9. #include<set>
  10. #include<map>
  11. #include<string>
  12. #include<math.h>
  13. #include<cctype>
  14.  
  15. using namespace std;
  16.  
  17. typedef long long ll;
  18. const int maxn=;
  19. const int INF=(<<);
  20. const double EPS=0.0000000001;
  21. const double Pi=acos(-1.0);
  22.  
  23. ll n;
  24. vector<ll> odd;
  25. bool isprime[maxn];
  26. vector<int> prime;
  27. const ll M=;
  28.  
  29. void play_prime()
  30. {
  31. memset(isprime,,sizeof(isprime));
  32. isprime[]=;
  33. for(int i=;i<maxn;i++){
  34. if(!isprime[i]) continue;
  35. for(int j=i*;j<maxn;j+=i){
  36. isprime[j]=;
  37. }
  38. }
  39. for(int i=;i<maxn;i++){
  40. if(isprime[i]) prime.push_back(i);
  41. }
  42. }
  43.  
  44. void dfs(int dep,ll cur)
  45. {
  46. odd.push_back(cur);
  47.  
  48. for(int i=dep;i<prime.size();i++){
  49. ll t=prime[i];
  50. if(t==){
  51. if(cur<=M/) dfs(i,cur*);
  52. else return;
  53. }
  54. else{
  55. if(cur<=M/(t*t)) dfs(i,cur*t*t);
  56. else return;
  57. }
  58. }
  59. }
  60.  
  61. int main()
  62. {
  63. int T;cin>>T;
  64. play_prime();
  65. dfs(,);
  66. sort(odd.begin(),odd.end());
  67. int tag=;
  68. while(T--){
  69. cin>>n;
  70. ll ans=upper_bound(odd.begin(),odd.end(),n)-odd.begin();
  71. printf("Case %d: %lld\n",tag++,n-ans);
  72. }
  73. return ;
  74. }

66 / 181 Problem E LightOJ 1282 Leading and Trailing

后三位直接用快数幂取余可以求出

前三位我们可以将n^k转化成a.bc * 10^m,这样abc就是前三位了,n^k =  a.bc * 10^m

即lg(n^k) = lg(a.bc * 10^m)

<==>k * lg(n) = lg(a.bc) + lg(10^m) = lg(a.bc) + m

m为k * lg(n)的整数部分,lg(a.bc)为k * lg(n)的小数部分

x = lg(a.bc) = k * lg(n) - m = k * lg(n) - (int)(k * lg(n))

a.bc = pow(10, x);

abc = a.bc * 100;

这样前三位数abc便可以求出

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<algorithm>
  6. #include<queue>
  7. #include<list>
  8. #include<cmath>
  9. #include<vector>
  10. using namespace std;
  11. long long POW(long long a,long long b,long long c){
  12. if(b==)return ;
  13. long long t=POW(a,b>>,c);
  14. t=t*t%c;
  15. if(b&)t=t*a%c;
  16. return t;
  17. }
  18. int main()
  19. {
  20. long long n,k,i,j,t,test=;
  21. scanf("%lld",&t);
  22. while(t--){
  23. scanf("%lld%lld",&n,&k);
  24. double m=k*log10(n)-(long long)(k*log10(n));
  25. m=pow(10.0,m);
  26. printf("Case %lld: %lld %03lld\n",test++,(long long)(m*),POW(n,k,));
  27. }
  28. return ;
  29. }

65 / 216 Problem F LightOJ 1259 Goldbach`s Conjecture

题意:给你一个偶数n,让你求它有多少种可能是两个素数相加得到的

思路:将10000000以内的素数打表,在开一个标志函数,要注意内存,用bool类型

  1. /*
  2. 筛法求素数
  3. */
  4. #include<iostream>
  5. #include<stdio.h>
  6. #include<math.h>
  7. #include<string.h>
  8. using namespace std;
  9.  
  10. const int MAXN=1e7+;
  11.  
  12. bool a[MAXN];
  13. int prime[MAXN/];
  14. int primeCnt;//素数个数
  15. void sieve(int n){//
  16. memset(a,true,sizeof(a));
  17. int i,j,k;
  18. k=sqrt(n);
  19. a[]=false;
  20. for(i=;i<=k;++i)
  21. if(a[i]==true){
  22. for(j=i+i;j<=n;j=j+i)
  23. a[j]=false;
  24. }
  25. primeCnt=;
  26. for(i=;i<=n;++i){
  27. if(a[i]==true){
  28. prime[primeCnt++]=i;
  29. }
  30. }
  31. }
  32.  
  33. int main(){
  34.  
  35. sieve(MAXN);
  36.  
  37. int T;
  38. int n;
  39. int i;
  40. int k;
  41. int sum;
  42. int ca=;
  43.  
  44. scanf("%d",&T);
  45.  
  46. while(T--){
  47. scanf("%d",&n);
  48. k=n/;
  49. sum=;
  50. for(i=;prime[i]<=k;++i){
  51. if(a[prime[i]]==true&&a[n-prime[i]]==true){
  52. ++sum;
  53. }
  54. }
  55. printf("Case %d: %d\n",++ca,sum);
  56. }
  57.  
  58. return ;
  59. }

65 / 110 Problem G LightOJ 1245 Harmonic Number (II)

先求出前sqrt(n)项和:即n/1+n/2+...+n/sqrt(n)

再求出后面所以项之和.后面每一项的值小于sqrt(n),计算值为1到sqrt(n)的项的个数,乘以其项值即可快速得到答案

例如:10/1+10/2+10/3+...+10/10

sqrt(10) = 3

先求出其前三项的和为10/1+10/2+10/3

在求出值为1的项的个数为(10/1-10/2)个,分别是(10/10,10/9,10/8,10/7,10/6),值为2个项的个数(10/2-10/3)分别是(10/5,10/4),在求出值为3即sqrt(10)的项的个数.

显然,值为sqrt(10)的项计算了2次,减去一次即可得到答案。当n/(int)sqrt(n) == (int)sqrt(n)时,值为sqrt(n)的值会被计算2次。

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cmath>
  4. using namespace std;
  5.  
  6. int main()
  7. {
  8. int T,n;
  9. scanf("%d",&T);
  10. long long sum;
  11. for(int i = ; i<=T; i++)
  12. {
  13. scanf("%d",&n);
  14. sum = ;
  15. for(int j = ; j<=sqrt(n); j++)
  16. {
  17. sum += n/j;
  18. }
  19. for(int j = ; j<=sqrt(n); j++)
  20. {
  21. sum += (n/j - n/(j+))*j;
  22. }
  23. if(n/(int)sqrt(n)==(int)sqrt(n))
  24. sum -= n/(int)sqrt(n);
  25. printf("Case %d: %lld\n",i,sum);
  26. }
  27. return ;
  28. }

48 / 172 Problem H LightOJ 1236 Pairs Forming LCM

思路:把n分解成素因数的形式n=p1^c1+p2^c2+...pm^cm

假设已找到一对(a,b)的lcm=n

有a=p1^d1+p2^d2+...pm^dm

b=p1^e1+p2^e2+...pm^em

易知max(di,ei)=ci

先考虑有序数对(a,b),由唯一分解定理知,a的每一个素因数的幂的大小都决定一个独一无二的数。

所以(a,b)的种数就是(di,ei)的种数,即2*(ci+1)-1(因为有序对(c1,c1)重复了一次所以-1)

所以有序对(a,b)的种数ans=(2*c1+1)*(2*c2+1)*(2*c3+1)*...*(2*cm+1)

但是要求求无序对的种数,已知(a,b)(b,a)重复,除了(n,n)只算了一个之外,所以ans = ans/2 +1

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<cstring>
  4. #include<algorithm>
  5. #include<cmath>
  6. using namespace std;
  7.  
  8. typedef long long ll;
  9. const int N = 1e7+;
  10. ll prime[N/];
  11. bool vis[N];
  12. int tot;
  13. void ini()
  14. {
  15. for(ll i=;i<N;i++)
  16. if(!vis[i])
  17. {
  18. prime[tot++]=i;
  19. for(ll j=i*i;j<N;j+=i) vis[j]=;
  20. }
  21. }
  22. int main()
  23. {
  24. ini();
  25. int T;
  26. scanf("%d",&T);
  27. for(int cas=;cas<=T;cas++)
  28. {
  29. ll n;
  30. cin>>n;
  31. ll t=n;
  32. ll ans=;
  33. for(int i=;i<tot&&prime[i]*prime[i]<=n;i++)
  34. {
  35. ll cnt=;
  36. while(t%prime[i]==) cnt++,t/=prime[i];
  37. ans*=(*cnt+);
  38. }
  39. if(t>) ans*=;
  40. ans = ans/ +;
  41. cout<<"Case "<<cas<<": "<<ans<<endl;
  42. }
  43. return ;
  44. }

43 / 73 Problem I LightOJ 1234 Harmonic Number

求1 + 1/2 + 1/3 + 1/4 + 1/ 5 +...+ 1/ n(1 ≤ n ≤ 108)

这题是单调级数部分求和,网上有公式,不过不知道公式也是没关系的,毕竟这个知识点也偏门了点。。。

我用的方法是打表记录1/i (1<=i<=n),根据题意,n最大为一亿,将一亿个结果记录下来肯定是不可行的,但是可以记录百万级个结果。下面的代码中,我开了一个250万的数组,0到一亿范围内,每40个数记录一个结果,即是分别记录1/40,1/80,1/120,...,1/一亿,这样对于输入的每个n,最多只需执行39次求倒数运算,大大节省了时间。

注意的是,a[0] = 0,只是为了使得当n==1时不用单独判断。

ps:当n很大时,有个近似公式:1+1/2+1/3+1/4+1/5+...+1/n=γ+ln(n) 
γ是欧拉常数,γ=0.57721566490153286060651209...
ln(n)是n的自然对数(即以e为底的对数,e=2.71828...)

我用这个公式写了下,好像精度不太够。

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <cstdio>
  4. #include <cstring>
  5. #include <cmath>
  6.  
  7. using namespace std;
  8.  
  9. const int maxn = ;
  10. double a[maxn] = {0.0, 1.0};
  11.  
  12. int main()
  13. {
  14. int t, n, ca = ;
  15. double s = 1.0;
  16. for(int i = ; i < ; i++)
  17. {
  18. s += (1.0 / i);
  19. if(i % == ) a[i/] = s;
  20. }
  21. scanf("%d", &t);
  22. while(t--)
  23. {
  24. scanf("%d", &n);
  25. int x = n / ;
  26. // int y = n % 40;
  27. s = a[x];
  28. for(int i = * x + ; i <= n; i++) s += (1.0 / i);
  29. printf("Case %d: %.10lf\n", ca++, s);
  30. }
  31. return ;
  32. }

38 / 160 Problem J LightOJ 1220 Mysterious Bacteria

题目大意:给你一个整数n(可能为负数),让你求满足a^p=n的最大的p
思路:当n是正数时,直接对n进行素因子分解,在对它的素因子的个数进行gcd,比如12=2^2*3,gcd(2,1)就是最大的p;
当n是负数时,则p的值一定是奇数,因为一个数的偶数次方一定为整数,因此需要将它的素因子个数全都化为奇数。

  1. #include<stdio.h>
  2. #include<string.h>
  3. const int MAXN=;
  4. bool vis[MAXN];
  5. long long prime[MAXN/];
  6. int tot=;
  7. void getPrime()//求素数
  8. {
  9. for(long long i=;i<MAXN;i++)
  10. if(!vis[i])
  11. {
  12. prime[tot++]=i;
  13. for(long long j=i*i;j<MAXN;j+=i) vis[j]=true;
  14. }
  15. }
  16. int a[];//保存素因子
  17. int b[];//保存素因子的个数
  18. int cnt;
  19. void sbreak(long long n){//进行素因子分解
  20. memset(a,,sizeof(a));
  21. memset(b,,sizeof(b));
  22. cnt=;
  23. for(int i=;prime[i]*prime[i]<=n;i++){
  24. if(n%prime[i]==){
  25. a[cnt]=prime[i];
  26. while(n%prime[i]==){
  27. b[cnt]++;
  28. n/=prime[i];
  29. }
  30. cnt++;
  31. }
  32. }
  33. if(n!=){
  34. a[cnt]=n;
  35. b[cnt++]=;
  36. }
  37. }
  38.  
  39. int gcd(int a,int b) //求最大公约数
  40. {
  41. return b?gcd(b,a%b):a;
  42. }
  43.  
  44. int main(){
  45. int T,ans,kase=,flag;
  46. long long n;
  47. getPrime();
  48. scanf("%d",&T);
  49. while(T--){
  50. flag=;//标志,判断n是正数还是负数
  51. scanf("%lld",&n);
  52. if(n<) n=-n,flag=;
  53. sbreak(n);
  54. int t=b[];
  55. if(!flag){//如果n是奇数
  56. if(t%==){
  57. while(t%==) t/=;
  58. }
  59. for(int i=;i<cnt;i++){//将它的素因子的个数化为奇数
  60. if(b[i]%==){
  61. while(b[i]%==) b[i]/=;
  62. }
  63. t=gcd(t,b[i]);
  64. }
  65. }
  66. else for(int i=;i<cnt;i++) t=gcd(t,b[i]);
  67. printf("Case %d: %d\n",++kase,t);
  68. }
  69. return ;
  70. }

46 / 98 Problem K LightOJ 1214 Large Division

d.问a能否被b整除

s.大数

c.借机水下java大数

  1. import java.math.BigInteger;
  2. import java.util.Scanner;
  3.  
  4. public class Main {//类名要用Main
  5. public static void main(String[] args){
  6.  
  7. int T;
  8. BigInteger a,b;
  9. BigInteger ZERO=new BigInteger("0");
  10. Scanner sc=new Scanner(System.in);
  11. int ca=0;
  12.  
  13. T=sc.nextInt();
  14. while((T--)>0){
  15.  
  16. a=sc.nextBigInteger();
  17. b=sc.nextBigInteger();
  18. System.out.print("Case ");
  19. System.out.print(++ca);
  20. if(a.remainder(b).compareTo(ZERO)==0){//b可能为负数,不能用mod函数
  21.  
  22. System.out.println(": divisible");
  23. }
  24. else{//
  25. System.out.println(": not divisible");
  26. }
  27.  
  28. }
  29.  
  30. }
  31. }

c2.大数模板,好臃肿啊!写起来也麻烦!用了下,还wa了好几发,很尴尬。%运算里面的d可能超int,得用long long才行,这种错不好找啊。。

ps:能少用这个就少用,代码太长。

  1. /*
  2. 整数大数
  3. int数组实现
  4. */
  5. #include<iostream>
  6. #include<stdio.h>
  7. #include<stdlib.h>
  8. #include<string.h>
  9. using namespace std;
  10.  
  11. #define MAXN 9999//万进制
  12. #define DLEN 4//4位
  13.  
  14. class BigNum{
  15. private:
  16. int a[];//可以控制大数位数(500*4)
  17. int len;//大数长度
  18. public:
  19. BigNum(){//构造函数
  20. len=;
  21. memset(a,,sizeof(a));
  22. }
  23. BigNum(const int);//将int转化为大数
  24. BigNum(const char *);//将字符串转化为大数
  25. BigNum(const BigNum &);//拷贝构造函数
  26. BigNum &operator=(const BigNum &);//重载赋值运算符,大数之间赋值
  27.  
  28. BigNum operator+(const BigNum &)const;//大数+大数
  29. BigNum operator-(const BigNum &)const;//大数-大数
  30. BigNum operator*(const BigNum &)const;//大数*大数
  31. BigNum operator/(const int &)const;//大数/int
  32.  
  33. BigNum operator^(const int &)const;//幂运算
  34. int operator%(const int &)const;//取模
  35. bool operator>(const BigNum &)const;//大数与大数比较
  36. bool operator>(const int &)const;//大数与int比较
  37.  
  38. void print();//输出大数
  39. };
  40.  
  41. BigNum::BigNum(const int b){//将int转化为大数
  42. int c,d=b;
  43. len=;
  44. memset(a,,sizeof(a));
  45. while(d>MAXN){
  46. //c=d-(d/(MAXN+1))*(MAXN+1);
  47. c=d%(MAXN+);//取出后四位
  48. d=d/(MAXN+);//
  49. a[len++]=c;
  50. }
  51. a[len++]=d;
  52. }
  53. BigNum::BigNum(const char *s){//将字符串转化为大数
  54. int t,k,index,l,i,j;
  55. memset(a,,sizeof(a));
  56. l=strlen(s);
  57. len=l/DLEN;
  58. if(l%DLEN)++len;
  59. index=;
  60. for(i=l-;i>=;i-=DLEN){
  61. t=;
  62. k=i-DLEN+;
  63. if(k<)k=;
  64. for(j=k;j<=i;++j)
  65. t=t*+s[j]-'';
  66. a[index++]=t;
  67. }
  68. }
  69. BigNum::BigNum(const BigNum &T):len(T.len){//拷贝构造函数
  70. int i;
  71. memset(a,,sizeof(a));
  72. for(i=;i<len;++i)
  73. a[i]=T.a[i];
  74. }
  75. BigNum &BigNum::operator=(const BigNum &n){//重载复制运算符,大数之间赋值
  76. int i;
  77. len=n.len;
  78. memset(a,,sizeof(a));
  79. for(i=;i<len;++i)
  80. a[i]=n.a[i];
  81. return *this;
  82. }
  83.  
  84. BigNum BigNum::operator+(const BigNum &T)const{//大数+大数
  85. BigNum t(*this);
  86. int i,big;//位数
  87. big=T.len>len?T.len:len;
  88. for(i=;i<big;++i){
  89. t.a[i]+=T.a[i];
  90. if(t.a[i]>MAXN){
  91. ++t.a[i+];
  92. t.a[i]-=MAXN+;
  93. }
  94. }
  95. if(t.a[big]!=)t.len=big+;
  96. else t.len=big;
  97. return t;
  98. }
  99. BigNum BigNum::operator-(const BigNum &T)const{//大数-大数
  100. int i,j,big;
  101. bool flag;
  102. BigNum t1,t2;//t1大的,t2小的
  103. if(*this>T){
  104. t1=*this;
  105. t2=T;
  106. flag=;//前面的大
  107. }
  108. else{
  109. t1=T;
  110. t2=*this;
  111. flag=;//前面的小
  112. }
  113. big=t1.len;
  114. for(i=;i<big;++i){
  115. if(t1.a[i]<t2.a[i]){
  116. j=i+;
  117. while(t1.a[j]==)++j;
  118. --t1.a[j--];
  119. while(j>i)t1.a[j--]+=MAXN;
  120. t1.a[i]+=MAXN+-t2.a[i];
  121. }
  122. else t1.a[i]-=t2.a[i];
  123. }
  124. while(t1.a[t1.len-]==&&t1.len>){
  125. --t1.len;
  126. --big;
  127. }
  128. if(flag)t1.a[big-]=-t1.a[big-];//前面的小,结果为负
  129. return t1;
  130. }
  131. BigNum BigNum::operator*(const BigNum &T)const{//大数*大数
  132. BigNum ret;
  133. int i,j,up;
  134. int temp,temp1;
  135. for(i=;i<len;++i){
  136. up=;
  137. for(j=;j<T.len;++j){
  138. temp=a[i]*T.a[j]+ret.a[i+j]+up;
  139. if(temp>MAXN){
  140. //temp1=temp-temp/(MAXN+1)*(MAXN+1);
  141. temp1=temp%(MAXN+);
  142. up=temp/(MAXN+);
  143. ret.a[i+j]=temp1;
  144. }
  145. else{
  146. up=;
  147. ret.a[i+j]=temp;
  148. }
  149. }
  150. if(up!=)ret.a[i+j]=up;
  151. }
  152. ret.len=i+j;
  153. while(ret.a[ret.len-]==&&ret.len>)--ret.len;
  154. return ret;
  155. }
  156. BigNum BigNum::operator/(const int &b)const{//大数/int
  157. BigNum ret;
  158. int i,down=;
  159. for(i=len-;i>=;--i){
  160. ret.a[i]=(a[i]+down*(MAXN+))/b;
  161. down=a[i]+down*(MAXN+)-ret.a[i]*b;
  162. }
  163. ret.len=len;
  164. while(ret.a[ret.len-]==&&ret.len>)--ret.len;
  165. return ret;
  166. }
  167.  
  168. BigNum BigNum::operator^(const int &n)const{//幂运算
  169. BigNum t,ret();
  170. int i;
  171. if(n<)exit(-);
  172. if(n==)return ;
  173. if(n==)return *this;
  174. int m=n;
  175. while(m>){
  176. t=*this;
  177. for(i=;i<<<=m;i<<=){
  178. t=t*t;
  179. }
  180. m-=i;
  181. ret=ret*t;
  182. if(m==)ret=ret*(*this);
  183. }
  184. return ret;
  185. }
  186. int BigNum::operator%(const int &b)const{//取模
  187. int i;
  188. long long d=;//这个题这里必须用long long,还得。。可能会超限。
  189. for(i=len-;i>=;--i){
  190. d=((d*(MAXN+))%b+a[i])%b;
  191. }
  192. return d;
  193. }
  194. bool BigNum::operator>(const BigNum &T)const{//大数与大数比较
  195. int ln;
  196. if(len>T.len)return true;
  197. else if(len==T.len){
  198. ln=len-;
  199. while(a[ln]==T.a[ln]&&ln>=)--ln;
  200. if(ln>=&&a[ln]>T.a[ln])return true;
  201. else return false;
  202. }
  203. else return false;
  204. }
  205. bool BigNum::operator>(const int &t)const{//大数与int比较
  206. BigNum b(t);
  207. return *this>b;
  208. }
  209.  
  210. void BigNum::print(){//输出大数
  211. int i;
  212. printf("%d",a[len-]);
  213. for(i=len-;i>=;--i){
  214. printf("%.4d",a[i]);//%.4d代表4位,不够前面补0
  215. }
  216. printf("\n");
  217. }
  218.  
  219. int main(){
  220. /*
  221. char str1[]="2",str2[]="22222222222222222222222222222222222222222222";
  222. int c=2;
  223. //scanf("%s%s",str1,str2);
  224. BigNum a,b,t;
  225. a=BigNum(str1);
  226. b=BigNum(str2);
  227. printf("a=");a.print();
  228. printf("b=");b.print();
  229. printf("c=%d\n",c);
  230. printf("\n");
  231.  
  232. t=a+b;
  233. printf("a+b=");t.print();
  234. t=a-b;
  235. printf("a-b=");t.print();
  236. t=a*b;
  237. printf("a*b=");t.print();
  238. t=a/c;
  239. printf("a/c=");t.print();
  240. printf("\n");
  241.  
  242. t=a^c;
  243. printf("a^c=");t.print();
  244. t=a%c;
  245. printf("a%%c=");t.print();
  246.  
  247. a>b?printf("a>b\n"):printf("a<=b\n");
  248. a>c?printf("a>c\n"):printf("a<=c\n");
  249. */
  250. int T;
  251. BigNum a;
  252. int b;
  253. char str1[];
  254. int t;
  255. int ca=;
  256.  
  257. scanf("%d",&T);
  258.  
  259. while(T--){
  260. scanf("%s%d",str1,&b);
  261. if(str1[]=='-'){
  262. a=BigNum(str1+);
  263. }
  264. else{
  265. a=BigNum(str1);
  266. }
  267. if(b<){
  268. b=-b;
  269. }
  270.  
  271. t=a%b;
  272. if(t==){
  273. printf("Case %d: divisible\n",++ca);
  274. }
  275. else{
  276. printf("Case %d: not divisible\n",++ca);
  277. }
  278. }
  279.  
  280. return ;
  281. }

c3.直接写也挺好啊~网上代码。里面的res也得用long long。

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5.  
  6. using namespace std;
  7.  
  8. char str[];
  9. long long mod;
  10.  
  11. int main()
  12. {
  13. int t;
  14. scanf("%d",&t);
  15. int cas = ;
  16. while( t-- )
  17. {
  18. scanf("%s %lld",str,&mod);
  19. //printf("%s %d\n",str,mod);
  20. int len = strlen( str );
  21. int s = ;
  22. if( str[] == '-' )
  23. s++;
  24. long long res = ;
  25. for( int i = s; i < len; i++ )
  26. {
  27. res = res* + str[i] - '';
  28. res = res % mod;
  29. }
  30. if( !res )
  31. printf("Case %d: divisible\n",++cas);
  32. else
  33. printf("Case %d: not divisible\n",++cas);
  34. }
  35. return ;
  36. }

35 / 62 Problem L LightOJ 1213 Fantasy of a Summation

题意:给你一个求和的循环,让你计算最后的结果是多少?

思路:首先,我们得明确在这个循环里面,a[0]……a[n-1]出现的次数是一样多的,
它大的累加的次数为n^k次方。
看第二个样例:
它有2个数字,3层循环
1、a[0]   a[0]   a[0]
2、a[0]   a[0]   a[1]
3、a[0]   a[1]   a[0]
4、a[0]   a[1]   a[1]
5、a[1]   a[0]   a[0]
6、a[1]   a[0]   a[1]
7、a[1]   a[1]   a[0]
8、a[1]   a[1]   a[1]
在这里面它的大的累加次数为2^3=8次,因为每个数的累加次数一样多的
它每个数的累加次数为(n^k)*k/n=(n^(k-1))*k,
则和就等于(sum(a[i])*(n^(k-1))*k)%mod

  1. #include<stdio.h>
  2. long long pow(int a,int n,int mod){
  3. if(n==) return ;
  4. long long t=pow(a,n/,mod);
  5. t=t%mod;
  6. long long ans=t*t%mod;
  7. if(n%==) ans=(ans*(a%mod))%mod;
  8. return ans;
  9. }
  10. int main(){
  11. int T,kase=;
  12. int a[];
  13. scanf("%d",&T);
  14. while(T--){
  15. int n,k,mod;
  16. long long ans=;
  17. scanf("%d%d%d",&n,&k,&mod);
  18. for(int i=;i<n;i++){
  19. scanf("%d",&a[i]);
  20. ans=(ans+a[i]%mod)%mod;
  21. }
  22. long long t=pow(n,k-,mod);
  23. ans=((ans*(k%mod)%mod)*t)%mod;
  24. printf("Case %d: %lld\n",++kase,ans);
  25. }
  26. return ;
  27. }

41 / 137 Problem M LightOJ 1197 Help Hanzo

给你a和b求a到b之间的素数个数。

先在小区间素数筛,大区间就用类似素数筛的想法,把a到b之间不是素数的标记出来。因为b-a最多1e5的大小,所以每组数据的时间复杂度最多就o(1e5 log1e5)。

ps:我感觉这个复杂度为O(1e5+log1e5)

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. using namespace std;
  5. const int MAXN = 2e5 + ;
  6. typedef long long LL;
  7. bool prime[MAXN] , vis[MAXN];
  8. LL p[MAXN / ];
  9.  
  10. void init() {
  11. prime[] = true;
  12. int cont = ;
  13. for(int i = ; i < MAXN ; i++) {
  14. if(!prime[i]) {
  15. p[++cont] = i;
  16. for(int j = i * ; j < MAXN ; j += i)
  17. prime[j] = true;
  18. }
  19. }
  20. }
  21.  
  22. int main()
  23. {
  24. init();
  25. int t , a , b;
  26. scanf("%d" , &t);
  27. for(int ca = ; ca <= t ; ca++) {
  28. scanf("%d %d" , &a , &b);
  29. int res = ;
  30. if(b < MAXN) {
  31. for(int i = a ; i <= b ; i++) {
  32. if(!prime[i])
  33. res++;
  34. }
  35. }
  36. else {
  37. memset(vis , false , sizeof(vis));
  38. for(int i = ; p[i]*p[i] <= b ; i++) {
  39. LL k = a / p[i];
  40. if(k*p[i] < a)
  41. k++;
  42. if(k == ) //此时a%p[i]==0 && a/p[i]==1,说明a刚好是一个素数
  43. k++;
  44. while(k * p[i] <= b) { //筛选a~b中不是素数的
  45. vis[k*p[i] - a] = true;
  46. k++;
  47. }
  48. }
  49. for(int i = a ; i <= b ; i++) {
  50. if(!vis[i - a])
  51. res++;
  52. }
  53. }
  54. printf("Case %d: %d\n" , ca , res);
  55. }
  56. }

45 / 100 Problem N LightOJ 1138 Trailing Zeroes (III)

d.给一个Q,代表N!末尾有Q个0。给出Q,找到最小的N。

s.可以用二分法,找到最小的N。

然后看看怎么求N!后面有几个0?

有算数基本定理可知 N!可划分为质因数相乘的形式  n!=2x*3y*5z*...

因为只有2*5才会出现0,又因为2的个数比5多(可见下面证明),所以N!后面的0的个数就是N!的分解中的5的个数。

那么如何求一个数的阶乘的结果5的幂次方是多少。

譬如30!的结果中,5的幂究竟是多少,答案是30/5 = 6, 6/5 = 1;结果为7个。除到最后的数<5为止。可以自己在纸上验证。

证明:2的个数比5多

对n!做质因数分解n!=2x*3y*5z*...

显然0的个数等于min(x,z),并且min(x,z)==z

对于阶乘而言,也就是1*2*3*...*n
[n/k]代表1~n中能被k整除的个数
那么很显然
[n/2] > [n/5] (左边是逢2增1,右边是逢5增1)
[n/2^2] > [n/5^2](左边是逢4增1,右边是逢25增1)
……
[n/2^p] > [n/5^p](左边是逢2^p增1,右边是逢5^p增1)
随着幂次p的上升,出现2^p的概率会远大于出现5^p的概率。
因此左边的加和一定大于右边的加和,也就是n!质因数分解中,2的次幂一定大于5的次幂。

  1. #include <stdio.h>
  2. #include <math.h>
  3. #include <vector>
  4. #include <queue>
  5. #include <string>
  6. #include <string.h>
  7. #include <stdlib.h>
  8. #include <iostream>
  9. #include <algorithm>
  10.  
  11. using namespace std;
  12.  
  13. typedef long long LL;
  14.  
  15. LL solve(LL n)
  16. {
  17. LL num=;
  18. while(n)
  19. {
  20. num+=n/;
  21. n/=;
  22. }
  23. return num;
  24. }
  25.  
  26. LL er(LL n)
  27. {
  28. LL x=;
  29. LL y=0x3f3f3f3f;
  30. LL mid;
  31. LL res=-;
  32. while(x<=y)
  33. {
  34. mid=(x+y)/;
  35. LL ans=solve(mid);
  36. if(ans==n)
  37. {
  38. res=mid;
  39. y=mid-;
  40. //return mid;
  41. }
  42. else if(ans>n)
  43. {
  44. y=mid-;
  45. }
  46. else if(ans<n)
  47. {
  48. x=mid+;
  49. }
  50. }
  51. return res;
  52. }
  53. int main()
  54. {
  55.  
  56. int t;
  57. scanf("%d",&t);
  58. int xp=;
  59. while(t--)
  60. {
  61. LL n;
  62. scanf("%lld",&n);
  63. LL ans=er(n);
  64. if(ans==-) printf("Case %d: impossible\n",xp++);
  65. else printf("Case %d: %lld\n",xp++,ans);
  66. }
  67. return ;
  68. }

37 / 48 Problem O UVA 11426 GCD - Extreme (II)

d.

G=0;
for(i=1;i<N;i++)
for(j=i+1;j<=N;j++)
{
G+=gcd(i,j);
}

求G。

s.假设a、b(a<b)互质,那么gcd(a,b)=1,这样当i循环到a、j循环到b时就会向结果中+1,而i循环到2*a、j循环到2*b时就会向结果中+2(gcd(2*a,2*b)=2)...循环到k*a和k*b时就会向结果中+k。这样实际上引起结果变化的根源就在于各对互质的数,当i、j循环到他们自身或者自身的倍数时就会引起结果的改变,那么我们不妨先将每对互质的数对结果的贡献值算出来,最后将各对互质的数对结果的贡献累加起来就可以了。

假设和b互质的数有n个,也就是n对(?,b)(?和b互质),那么在i、j循环到?、b时结果会增加n,循环到(2*?,2*b)时结果就会增加2*n...当i、j循环到k*?、k*b时结果就会增加k*n。那么我们不妨用a[i]记录各种k、b在满足k*b=i时会增加多少结果,a[i]代表gcd(x,i)的和,其中x小于i,那么最后我们要输出的就是a[2]+a[3]+...+a[N]。

至于找和b互质的数,就是计算b的欧拉函数的值,然后暴力循环k,并修改对应的a[k*b]即可,整体的复杂度是O(N*logN)的。

欧拉函数扩展: 欧拉公式的延伸:小于n 与n互质的数的和 是euler(n)*n/2

  1. //欧拉函数复杂度O(nlogn)
  2. #include<stdio.h>
  3. #include<string.h>
  4. #include <iostream>
  5. using namespace std;
  6. #define MAXD 4000010
  7. const int N = ;
  8. typedef long long LL;
  9. int phi[MAXD];
  10. LL a[MAXD];
  11.  
  12. void prep()
  13. {
  14. memset(a, , sizeof(a));
  15. for(int i = ; i <= N; i ++)
  16. phi[i] = i;
  17. for(int i = ; i <= N; i ++)
  18. {
  19. if(phi[i] == i){ ///质数
  20. for(int j = i; j <= N; j += i){
  21. phi[j] = phi[j] / i * (i - );
  22. }
  23. }
  24. for(int j = ; j * i <= N; j ++)
  25. a[j * i] += j * phi[i]; ///通过对i*j的质因子来求
  26. }
  27. for(int i = ; i <= N; i ++)
  28. a[i] += a[i - ];
  29. }
  30.  
  31. int main()
  32. {
  33. prep();
  34. int n;
  35. while(scanf("%d", &n), n)
  36. printf("%lld\n", a[n]);
  37. return ;
  38. }

13 / 65 Problem P UVA 11754 Code Feat
9 / 26 Problem Q UVA 11916 Emoogle Grid
36 / 86 Problem R POJ 1061 青蛙的约会

s.设A在后,B在前,当A与B相遇时,满足:(m-n)*X=(y-x)+L*Y;X是时间,Y是圈数。

移项:(m-n)*X-L*Y=(y-x);

令a=m-n,b=-L,d=gcd(a,b)。则(y-x)%d==0时有解,否则无解。

求出特解,再求最小的X即可。

  1. /*
  2. 扩展欧几里德算法(求ax+by=gcd的解以及逆元)
  3. */
  4. #include<iostream>
  5. #include<stdio.h>
  6. #include<stdlib.h>
  7. using namespace std;
  8.  
  9. //返回d=gcd(a,b);和对应于等式ax+by=d中的x,y
  10. long long extend_gcd(long long a,long long b,long long &x,long long &y){
  11. if(a==&&b==)return -;//无最大公约数
  12. if(b==){x=;y=;return a;}
  13. long long d=extend_gcd(b,a%b,y,x);
  14. y-=a/b*x;
  15. return d;
  16. }
  17.  
  18. int main(){
  19.  
  20. int x,y,m,n,L;
  21. long long a,b,x0,y0,d;
  22. long long abs_bd;
  23.  
  24. while(~scanf("%d%d%d%d%d",&x,&y,&m,&n,&L)){
  25. a=m-n;
  26. b=-L;
  27. d=extend_gcd(a,b,x0,y0);
  28.  
  29. abs_bd=abs(b/d);
  30.  
  31. if((y-x)%d==){
  32. x0=(x0*((y-x)/d))%b;
  33. //x0=(x0%(b/d)+(b/d))%(b/d);
  34. x0=(x0%abs_bd+abs_bd)%abs_bd;
  35. printf("%lld\n",x0);
  36. }
  37. else{
  38. printf("Impossible\n");
  39. }
  40. }
  41.  
  42. return ;
  43. }

24 / 63 Problem S POJ 2115 C Looooops

hint:见之前博客

13 / 35 Problem T POJ 2116 Death to Binary?
61 / 122 Problem U HDU 2161 Primes

输入n,是素数输出yes,不是则输出no。

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <cmath>
  5. using namespace std;
  6.  
  7. int p[];
  8.  
  9. int main()
  10. {
  11. int n,k=;
  12. memset(p,-,sizeof(p));
  13. p[]=;
  14. p[]=;
  15. for(int i=; i<=; i++)
  16. {
  17. for(int j=; j<=sqrt(i); j++)
  18. {
  19. if(i%j==)
  20. {
  21. p[i]=;
  22. break;
  23. }
  24. }
  25. }
  26.  
  27. while(~scanf("%d",&n))
  28. {
  29. if(n<=)
  30. return ;
  31. if(p[n]==-)
  32. printf("%d: yes\n",++k);
  33. else
  34. printf("%d: no\n",++k);
  35. }
  36.  
  37. return ;
  38. }

32 / 87 Problem V UVA 11827 Maximum GCD

题意:给你一组数,求出其中两两最大公约数中最大的值。

思路:数据较小,直接枚举。

  1. #include<stdio.h>
  2. int gcd(int a,int b){//求最大公约数
  3. return b?gcd(b,a%b):a;
  4. }
  5. int main(){
  6. int T;
  7. int a[];
  8. char c;
  9. scanf("%d",&T);
  10. while (getchar() != '\n');
  11. while(T--){
  12. int cnt=;
  13. while((c=getchar())!='\n'){
  14. if(c>='' && c<=''){
  15. ungetc(c,stdin);//将字符c退回到输入流中
  16. scanf("%d",&a[cnt++]);
  17. }
  18. }
  19. int max=;
  20. for(int i=;i<cnt-;i++){
  21. for(int j=i+;j<cnt;j++){
  22. int t=gcd(a[i],a[j]);
  23. if(t>max) max=t;
  24. }
  25. }
  26. printf("%d\n",max);
  27. }
  28. return ;
  29. }

25 / 98 Problem W UVA 10200 Prime Time

题意:通过公式计算出一个数,判断这个数是否为素数。在区间[a,b]上通过公式算出素数占总数的百分比。

ps:里面加上1e-8是什么梗

  1. #include <stdio.h>
  2. #include <string.h>
  3. int prime(int n)
  4. {
  5. int i;
  6. for(i=;i*i<=n;i++)
  7. {
  8. if((n%i)==)
  9. return ;
  10. }
  11. return ;
  12. }
  13. int main()
  14. {
  15. int num[];
  16. int i;
  17. int a,b;
  18. int sum;
  19. memset(num,,sizeof(num));
  20. for(i=;i<=;i++)
  21. num[i]=prime(i*i+i+);
  22. while(scanf("%d%d",&a,&b)!=-)
  23. {
  24. sum=;
  25. for(i=a;i<=b;i++)
  26. sum+=num[i];
  27. printf("%.2f\n",sum*1.0/(b-a+)*+1e-);//精度
  28. }
  29. return ;
  30. }

20 / 154 Problem X SGU 106 The equation
34 / 51 Problem Y POJ 2478 Farey Sequence

题意:给定一个数n,求小于或等于n的数中两两互质组成的真分数的个数。 表达的有点挫,很直接的欧拉函数的应用。

phi(x) 表示与x互质且小于x的正整数的个数。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cmath>
  4. #include<cstring>
  5. #include<algorithm>
  6. #define see(x) cout<<#x<<":"<<x<<endl;
  7. #define MAXN 1000005
  8. using namespace std;
  9.  
  10. int prime[MAXN],phi[MAXN];
  11. bool notp[MAXN];
  12. void Prime(){
  13. int i, j, np=;
  14. phi[] = ;
  15. memset(notp,false,sizeof(notp));
  16. for(i=;i<MAXN;i++){
  17. if(notp[i]==false){
  18. prime[np++] = i;
  19. phi[i] = i-;
  20. }
  21. for(j=;j<np&&i*prime[j]<MAXN;j++){
  22. notp[i*prime[j]] = true;
  23. if(i%prime[j]==){
  24. phi[i*prime[j]] = phi[i]*prime[j];
  25. break;
  26. }
  27. else{
  28. phi[i*prime[j]] = phi[i]*(prime[j]-);
  29. }
  30. }
  31. }
  32. }
  33.  
  34. long long ans[MAXN];
  35. int main(){
  36. int n, i;
  37. Prime();
  38. ans[] = ;
  39. for(i=;i<MAXN;i++){
  40. ans[i] = ans[i-] + phi[i];
  41. }
  42. while(scanf("%d",&n)&&n){
  43. cout<<ans[n]<<endl;
  44. }
  45. return ;
  46. }

这里要说到关于筛素数的方法。以下算法复杂度为O(n)

  1. void Prime(){
  2. int i, j, np=;
  3. memset(notp,false,sizeof(notp));
  4. for(i=;i<MAXN;i++){
  5. if(notp[i]==false){
  6. prime[np++] = i;
  7. }
  8. for(j=;j<np&&i*prime[j]<MAXN;j++){
  9. notp[i*prime[j]] = true;
  10. if(i%prime[j]==){ //O(n)的关键
  11. break;
  12. }
  13. }
  14. }
  15. }

适时跳出,大大降低了算法复杂度。本质就是任意一个合数都有一个最小质因数,最终被赋值为true时,都是由其的最小质因数筛出来的,其被筛出来后也无需再关心其他数了。

原因如下:设 i 的最小质因数为p[j],则 i%p[j]==0,设k=i/p[j],w=i*p[j]=k*p[j]*p[j],w是由k*p[j]和p[j]共同筛出来的,对于比w更大的也有因子p[j]的数ww,则自然可以由后面的m*p[j](m>k)和p[j]共同筛出来了。

对筛素数的代码,略加几行代码,就可以顺带求出欧拉函数phi[x]了。用到了递推式:

对于p|x。若p2|x,则phi(x) = phi(x/p)*p;否则phi(x) = phi(x/p)*(p-1)

23 / 63 Problem Z UVA 11752 The Super Powers

题目大意:没有输入,找出所有的超级数,超级数即可以拆分成至少两个数的幂形式。

解题思路:先用素数筛选法找出64以内的合数,以为只有幂是合数才可以进行拆分。然后枚举底数进行判断,所有小于2^64-1的数都是满足的,这里有一个技巧,就是说2^64-1已经是unsign long long 的最大值了,那么超过它的数就会变成负数。但其实i的最大次幂是可以求的,x = logi(2^64-1) = log(2^64-1) / log(i);

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <math.h>
  4. #include <set>
  5. #include <algorithm>
  6.  
  7. using namespace std;
  8. typedef unsigned long long ll;
  9. const int N = ;
  10. int g, v[N], a[N];
  11.  
  12. void init () {
  13. g = ;
  14. memset(v, , sizeof(v));
  15.  
  16. for (int i = ; i <= ; i++) {
  17. if (v[i]) {
  18. a[g++] = i;
  19. continue;
  20. }
  21.  
  22. for (int j = i * ; j <= ; j += i) v[j] = ;
  23. }
  24. }
  25.  
  26. void solve () {
  27. set<ll> ans;
  28. ans.insert();
  29.  
  30. ll MaxT = <<;
  31. for (ll i = ; i < MaxT; i++) {
  32. int ti = ceil( * log() / log(i)) - ;
  33. ll now = i * i * i * i;
  34. ans.insert(now);
  35. for (int j = ; a[j] <= ti; j++) {
  36. now *= (a[j] - a[j-] == ? i : i * i);
  37. ans.insert (now);
  38. }
  39. }
  40.  
  41. for (set<ll>::iterator i = ans.begin(); i != ans.end(); i++)
  42. printf("%llu\n", *i);
  43. }
  44.  
  45. int main () {
  46. init();
  47. solve ();
  48. return ;
  49. }

[kuangbin带你飞]专题十四 数论基础的更多相关文章

  1. 「kuangbin带你飞」专题十四 数论基础

    layout: post title: 「kuangbin带你飞」专题十四 数论基础 author: "luowentaoaa" catalog: true tags: mathj ...

  2. [kuangbin带你飞]专题十 匹配问题

        A-L 二分匹配 M-O 二分图多重匹配 P-Q 二分图最大权匹配 R-S 一般图匹配带花树 模板请自己找     ID Origin Title   61 / 72 Problem A HD ...

  3. [kuangbin带你飞]专题十 匹配问题 一般图匹配

    过去做的都是二分图匹配 即 同一个集合里的点 互相不联通 但是如果延伸到一般图上去 求一个一般图的最大匹配 就要用带花树来解决 带花树模板 用来处理一个无向图上的最大匹配 看了一会还是不懂  抄了一遍 ...

  4. [kuangbin带你飞]专题十五 数位DP

            ID Origin Title   62 / 175 Problem A CodeForces 55D Beautiful numbers   30 / 84 Problem B HD ...

  5. [kuangbin带你飞]专题十 匹配问题 二分匹配部分

    刚回到家 开了二分匹配专题 手握xyl模板 奋力写写写 终于写完了一群模板题 A hdu1045 对这个图进行 行列的重写 给每个位置赋予新的行列 使不能相互打到的位置 拥有不同的行与列 然后左行右列 ...

  6. [kuangbin带你飞]专题十 匹配问题 二分图多重匹配

    二分图的多重匹配问题不同于普通的最大匹配中的"每个点只能有最多一条边" 而是"每个点连接的边数不超过自己的限定数量" 最大匹配所解决的问题一般是"每个 ...

  7. 【算法系列学习】DP和滚动数组 [kuangbin带你飞]专题十二 基础DP1 A - Max Sum Plus Plus

    A - Max Sum Plus Plus https://vjudge.net/contest/68966#problem/A http://www.cnblogs.com/kuangbin/arc ...

  8. [kuangbin带你飞]专题十六 KMP & 扩展KMP & Manacher 题解报告

    来刷kuangbin字符串了,字符串处理在ACM中是很重要的,一般比赛都会都1——2道有关字符串处理的题目,而且不会很难的那种,大多数时候都是用到一些KMP的性质或者找规律. 点击标题可跳转至VJ比赛 ...

  9. [kuangbin带你飞]专题十二 基础DP1

            ID Origin Title   167 / 465 Problem A HDU 1024 Max Sum Plus Plus   234 / 372 Problem B HDU 1 ...

随机推荐

  1. struts2介绍

    struts2简介 Struts2框架发展 Struts于2000年5月由Craig McClanahan发起,并于 2001年7月发布了1.0版本,Struts一出现便大受欢迎,更成为了以后几年内w ...

  2. JavaScript:改变li前缀图片和样式

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stri ...

  3. 局域网怎么通过IP查看对方MAC

    在cmd命令状态查输 入:nbtstat -a IPIP地址就是你所需要查询的IP地址,如192.168.1.200,效果如下图:

  4. javascript 返回数组中不重复的元素

    这是实现结构伪类type-of-type的部分代码: <script type="text/javascript"> var ret= ["span" ...

  5. C#Winform中treeView控件使用总结

    1.如何展开结点时改变图标(注意:不是选中时) 要在目录中使用图标首先要加入一个控件ImageList(命名为imageList1),然后可以按图片的index或名称引用图片. 然后需要在TreeVi ...

  6. Java自带工具jstack故障分析的一个案例

    公司的一个web应用项目运行了很长一段时间,达半年之久,前段时间突然出现了服务不可用的情况,所有的请求都不可达,服务彻底挂了.查看tomcat进程还在,cpu使用率低,一时没找着问题,重启了服务.过了 ...

  7. OC中的self指针

    在OC中,self是一个指针,方法和属性可以通过self.function进行访问:成员变量使用self->变量名进行访问.调用方法还可以用[self function]; OC中的self有点 ...

  8. JS如何调用隐藏按钮的click事件

    js如何调用隐藏按钮的click事件:1.设定隐藏不要使用Visiable属性,使用style.display=none:2.触发JS事件可以使用fireEvent方法,如:document.getE ...

  9. RDO部署openstack(3)

    目前OpenStackNeutron框架支持的网络服务有:LoadBalancing as a Service,VPNas a Service,Firewallas a Service. 1. 安装和 ...

  10. WPF性能提高--MSDN学习摘要

    关于性能 一.    关于硬件加速 1.对于大多数图形硬件而言,大型图面是指达到 2048x2048 或 4096x4096 像素大小的图面. 二.    合理的布局 1.简单地说,布局是一个递归系统 ...