题意:
求区间质数的个数。
分析:
简单的质数打表模板题,根据题目再添加一点限制条件即可AC。
因为m最大才1e6,所以打表是可以的。
简单说说打表的思路:(埃式筛法)
从最小的质数2开始,将表中所有2的倍数都划去,然后再到质数3,将表中所有3的倍数都划去......以此类推。
0,1先特殊处理一下。
1 // 参考《挑战程序设计竞赛》P119 2 bool is_prime[1000005]; 3 int prime[1000005]; 4 5 // O(nloglogn) 6 void prime_table(){ // 这里的范围定义为 1e6 7 is_prime[0] = is_prime[1] = false; // 特殊处理 0,1 8 for(int i = 2; i <= 1000000; i++) is_prime[i] = true; 9 for(int i = 2; i <= 1000000; i++){ 10 if(is_prime[i]){ 11 // 把 质数i 的倍数从表里划去 12 for(int j = i+i; j <= 1000000; j+=i) is_prime[j] = false; 13 } 14 } 15 }
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 5 int n, m; 6 bool is_prime[1000005]; 7 8 void sieve(){ 9 for(int i = 0; i <= 1000000; i++) is_prime[i] = true; 10 is_prime[0] = is_prime[1] = false; 11 for(int i = 2; i <= 1000000; i++){ 12 if(is_prime[i]){ 13 // prime[p++] = i; 14 for(int j = 2 * i; j <= 1000000; j+=i) is_prime[j] = false; 15 } 16 } 17 } 18 19 int main() 20 { 21 sieve(); 22 while(cin >> n >> m){ 23 int l, r, ans; 24 for(int a = 0; a < n; a++){ 25 cin >> l >> r; 26 ans = 0; 27 if(l > m || r > m || l <= 0 || r <= 0){ 28 cout << "Crossing the line "; 29 } 30 else{ 31 for(int i = l; i <= r; i++){ 32 if(is_prime[i]) ans++; 33 } 34 cout << ans << endl; 35 } 36 } 37 } 38 return 0; 39 }
下一题:
题意:
在n个数中(每个数的大小以次是1~n)中,找到k个数中的最大公约数。
分析:
(请拿出笔和纸来一起列下式子分析下,如果是数学大牛的话,请忽略这段话)
(感谢kkkse03的题解)
在n个数里,每个数的大小是1,2,3,...,n-1,n;
所取的k个数分别是X1,X2,X3,...,Xk-1, Xk;
设最大公约数为a,
则有 X1 >= 1a, X2 >= 2a,...,Xk >= ka ①;
同时又因为 Xk <= n ②
又①②得 ka <= n,转换一下就是 a <= [n/k] ([]为取整符号)
另外,取[n/k],2*[n/k],3*[n/k],...,k*[n/k],满足最大公约数a = [n/k],且都小于等于n大于等于1,且互不相等,满足条件。
(如果觉得还不清楚请看洛谷题解吧dbq)
因此这就被当作是入门难度的题目处理了(代码确实很短)
1 #include<iostream> 2 using namespace std; 3 4 int main() 5 { 6 int n, k; 7 while(cin >> n >> k){ 8 cout << n / k << endl; 9 } 10 return 0; 11 }
也是一道辗转相除法的题目,运用了辗转相除法的思想:
公约数a, y = ax + b (y >= ax)
这样的思维才得出了以上关系式。
下一题:
题意:
一天,CC买了N个容量可以认为是无限大的瓶子,开始时每个瓶子里有1升水。接着~~CC发现瓶子实在太多了,于是他决定保留不超过K个瓶子。每次他选择两个当前含水量相同的瓶子,把一个瓶子的水全部倒进另一个里,然后把空瓶丢弃。(不能丢弃有水的瓶子)
显然在某些情况下CC无法达到目标,比如N=3,K=1。此时CC会重新买一些新的瓶子(新瓶子容量无限,开始时有1升水),以到达目标。
现在CC想知道,最少需要买多少新瓶子才能达到目标呢?
分析:
相同容量时的瓶子才能合二为一→二叉树状图→2的次方!
要最少的瓶子就是2的次方数相加的和比N大的最小值。
N不是2的次方数的情况:
留k瓶水,则要找k个2的次方数,
当k!=1时,找比k/2大的2的次方数,然后N减去这个2的次方数;
当k==1时,找比k大的2的次方数;
N是2的次方数的情况:
只要确认下N是不是2的次方数即可输出0;
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 using namespace std; 5 6 long long n, k; 7 8 int main() 9 { 10 while(cin >> n >> k){ 11 long long num, ans; 12 while(k>0 && n > 0){ 13 num = 1; 14 if(k == 1){ 15 while(num < n){ 16 num *= 2; 17 if(num == n) ans = 0; 18 // printf("k:%lld n:%lld num:%lld ", k, n, num); 19 20 } 21 ans = num - n; 22 // printf("k:%d n:%d num:%d ", k, n, num); 23 } 24 else { 25 while(num <= n / 2){ 26 num *= 2; 27 } 28 // printf("k:%d n:%d num:%d ", k, n, num); 29 n -= num; 30 ans = n; 31 } 32 k--; 33 } 34 cout << ans << endl; 35 } 36 return 0; 37 }
下一题:
题意:
分析:
题目很好懂,但怎么想都觉得很麻烦,因为N<=40000,不能开二维数组。
(作者unsigned说这是一道欧拉函数题,tql)
对unsigned的题解上的补充。
欧拉函数(Eular(int n))的效果是输出比n小与n互质的个数。
公式是:
右式= x(1-1/p1)(i-1/p2)*...*(1-1/pn);
为了防止爆数可以这样处理:
右式=x*p1(p1-1)*p2(p2-1)*...*pn(pn-1);
1 int eular(int n) 2 { 3 int ret=1,i; 4 for(i=2;i*i<=n;i++) // 运用 筛法, 找 n 的因数 5 { 6 if(n%i==0) // i 是 n 的因数, 且是质数 7 { 8 n/=i,ret*=i-1; 9 while(n%i==0) n/=i,ret*=i; 10 } 11 } 12 if(n>1) ret*=n-1; // n 本身变成了质数或者本来就是质数 13 return ret; 14 }
1 void phi_table() 2 { 3 phi[0] = 0, phi[1] = 1; // 1的欧拉函数值为1, 唯一与1互质的数 4 for(int i = 2; i < maxn; i++) phi[i] = i; // 先初始化为其本身 5 for(int i = 2; i < maxn; i++){ 6 if(phi[i] == i){ // 如果欧拉函数值仍为其本身, 说明i为素数 7 for(int j = i; j < maxn; j += i)// 把i的欧拉函数值改变, 同时也把能被素因子i整除的数的欧拉函数值改变 8 phi[j] = phi[j] / i * (i - 1); 9 } 10 } 11 }
1 // 感谢 unsigned作者 精彩的分析 2 #include<cstdio> 3 #include<iostream> 4 using namespace std; 5 6 int n; 7 int prime[40002]; 8 9 void phi_table(){ 10 for(int i = 0; i <= 40000; i++) prime[i] = i; 11 for(int i = 2; i <= 40000; i++){ 12 if(prime[i] == i){ 13 for(int j = i; j <= 40000; j += i) 14 prime[j] = prime[j] / i * (i - 1); 15 } 16 } 17 } 18 19 int main() 20 { 21 phi_table(); 22 while(cin >> n){ 23 if(n == 1) { cout << 0 << endl; continue; } 24 else{ 25 int ans = 2; 26 for(int i = 2; i < n; i++) ans += prime[i] * 2; 27 cout << ans + 1 << endl; 28 } 29 } 30 return 0; 31 }
今天收获:
复习了与gcd,质数,欧拉函数有关的数学题,数学题要多写,找规律。
(数学不太好的我太吃亏了)