【ACM】kuangbin基础数论专题
知识补充:裴蜀定理
1.Bi-shoe and Phi-shoe
1.题意
给出一行数,求对应的数的欧拉函数值大于给出的数的数的最小和。
2.思路
我们知道素数表的欧拉函数值递增。
设素数a,b,b是a的下一个素数,则phi[a]<ph[b],且a-b间的所有数的欧拉函数都小于等于phi[a]。
欧拉函数值大于x的数的最小的数就是大于x的最小的素数
3.代码
#include"bits/stdc++.h"
using namespace std;
typedef long long LL;
const int N = 1001005;
int prime[N],cnt;
bool st[N];
int c=1;
void Prime(int n){st[0] = st[1] = 1;for(int i = 2; i <= n; ++i){if(!st[i]) prime[cnt++]=i;for(int j = 0; prime[j]<= n/i; ++j){st[i*prime[j]] = 1;if(i%prime[j]==0) break;}}
}
int main(){int t;cin >> t;Prime(N);while(t--){int n;cin >> n;LL ans=0;for(int i = 0; i < n; ++i){int x;cin >> x;for(int j = x+1; ;++j){if(!st[j]) { //如果是素数ans+=j;break;}}}printf("Case %d: %lld Xukha\n",cnt++,ans);}return 0;
}
2.Prime Independence
1.题意
2.思路
3.代码
3.Aladdin and the Flying Carpet
1.题意
给出整数 a 和 b ,求区间[b, a] 内的 a 的约数对的个数,即:满足c*d == a 且 c>=b,d>=b。a 的约数对(比如[2, 5] 与 [5, 2] 为同一对)。
2.思路
线性筛+唯一分解定理
根据唯一分解定理,先将a唯一分解,则a的所有正约数的个数为num = (1 + a1) * (1 + a2) *…(1 + ai),这里的ai是素因子的指数,见唯一分解定理,因为题目说了不会存在c==d的情况,因此num要除2,去掉重复情况,然后枚举小于b的a的约数,拿num减掉就可以了。
3.代码
#include"bits/stdc++.h"
#define s(a) scanf("%d",&a)
#define sl(a) scanf("%lld",&a)
#define sl2(a,b) scanf("%lld%lld",&a,&b)
using namespace std;
typedef long long ll;
const int MAXN = 1000010;
int prime[MAXN];
bool vis[MAXN];
int t;
int cnt=1;
int num=0;
void Prime(int n){memset(vis,0,sizeof(vis));vis[0] = vis[1] = 1;for(int i = 2; i <= n; ++i){if(!vis[i]) prime[cnt++] = i;for(int j = 1; j <= cnt && i*prime[j]<=n ; ++j){vis[i*prime[j]] = 1; //prime[j]是素数,他的倍数也是素数 if( i%prime[j] == 0) break; //i是某个素数的倍数,直接跳出 }}
}
ll getfac(ll x)
{ll ans=1;for(int i=1;prime[i]<=x/prime[j];i++){ll sum=0;//当前质因数的幂指数while(x%prime[i]==0)//当是这个数的因子时{sum++;x/=prime[i];}ans*=(sum+1);//应用定理的结论}if(x>1)//当搜索不到的时候,如果这个数最后大于一,那么这个最后结果肯定是素数,并且指数是1ans*=2;return ans;
}int main(){Prime(MAXN);s(t);while(t--) {ll a, b;scanf("%lld%lld",&a,&b);if(a<b*b) {printf("Case %d: 0\n",++num);continue;}ll ans = getfac(a)/2;for(ll i = 1; i < b; ++i)if(a%i==0) ans--;printf("Case %d: %lld\n",++num,ans);}return 0;
}
4.Sigma Function
1.题意
求从1-n的数中约数和是偶数的数的个数
2.思路
1-100打表
不满足的数/和
1 1
2 3
4 7
8 15
9 13
16 31
18 39
25 31
32 63
36 91
49 57
50 93
64 127
72 195
81 121
98 171
100 217
发现100中,因子和为奇数的有:
1 2 4 6 9 16 18 25 32 36 49 50 64 72 81 98 100
有没有发现,这些数字有一个规律,他们是 x^2, 2x, 2x^2, 只要100中的数满足这三个中的一个,那么,这个数就是不满足的,
总数-不满足的个数 = 满足的个数
我们还可以发现:
当x为偶数时2x和x^2会有重复的部分
当x为奇数时2x和2*x^2会有重复的部分
最后发现x^2和 2x^2涵盖了所有情况,且不重复,因此减去这两中情况的数目即可
3.代码
#include "bits/stdc++.h"
#define s(a) scanf("%d",&a)
#define sl(a) scanf("%lld",&a)
#define s2(a,b) scanf("%d%d",&a,&b)
#define sl2(a,b) scnaf("%lld%lld",&a,&b)
using namespace std;
typedef long long ll;
int cnt=1;
int main(){int t;cin>>t;while(t--){ll n;cin>>n;ll ans=0;ll x = sqrt(n);ll y = sqrt(1.0*n/2);ans=n-x-y;printf("Case %d: %lld\n",cnt++, ans);}return 0;
}
5.Leading and Trailing
1.题意
求n^k前三位和后三位
2.思路
1.暴力跑肯定超时
2.后三位好求,n^k%1000即可
前三位需要变形:参考大佬的推导
接下来我们求k+lgn即可
怎么求呢,有个函数学习一下modf()
求出小数部分b后,计算一下就好啦,不过要注意最后要输出3位,需要控制一下输出格式,当n^k=10000000时,对1000取余结果为0,需要再补2个0
3.代码
#include "bits/stdc++.h"#define s(a) scanf("%d",&a)#define sl(a) scanf("%lld",&a)#define s2(a,b) scanf("%d%d",&a,&b)#define sl2(a,b) scanf("%lld%lld",&a,&b)using namespace std;typedef long long ll;int t, cnt=1;double x,y;ll n,k;ll quick_mod(ll a,ll b,ll p){ll num=a,sum=1;while(b){if(b&1) sum=sum*num%p;num=num*num%p;b>>=1;}return sum;}///a^b mod p*/int main(){//freopen("d://data.txt" ,"w" ,stdout);cin>>t;while(t--){cin>>n>>k;y = modf((double)(k*log10(n)),&x);ll ans1 = pow(10,y)*100;ll ans2=quick_mod(n,k,1000);printf("Case %d: %03lld %03lld\n",cnt++, ans1,ans2);}return 0;}
//注意输出格式,后三位可能存在最大位为十位或个位,需要补0
6.Goldbach`s Conjecture
1.题意
求n=a+b且a,b都是素数这样的a,b的对数
2.思路
素数筛模板题
遍历素数表prime[i],若n-prime[i]也是素数,ans++
prime[i]>n/2时结束,因为后面再跑就重复了嘛
3.代码
#include "bits/stdc++.h"#define s(a) scanf("%d",&a)
#define sl(a) scanf("%lld",&a)
#define s2(a, b) scanf("%d%d",&a,&b)
#define sl2(a, b) scanf("%lld%lld",&a,&b)
using namespace std;
typedef long long ll;
int t, c = 1;
const int MAXN = 1e7+10;
int prime[1000000];
bool vis[MAXN];
int cnt = 0;
void Prime(int n) {memset(vis, 0, sizeof(vis));vis[0] = vis[1] = 1;for (int i = 2; i <= n; ++i) {if (!vis[i]) prime[cnt++] = i;for (int j = 0; j < cnt && i * prime[j] <= n; ++j) {vis[i * prime[j]] = 1; //prime[j]是素数,他的倍数也是素数if (i % prime[j] == 0) break; //i是某个素数的倍数,直接跳出}}
}int main() {//freopen("d://data.txt" ,"w" ,stdout);Prime(MAXN);cin >> t;while (t--) {int n,ans=0;cin >> n;for(int i =0; i < cnt; ++i){if(prime[i]>n/2) break;if(!vis[n-prime[i]]) ans++;}printf("Case %d: %d\n",c++, ans);}return 0;
}
7.Harmonic Number (II)
1.题意
求n*(1+1/2+1/3+…+1/n)
2.思路
分块数论
3.代码
#include"bits/stdc++.h"
using namespace std;
typedef long long ll;
int t,cnt= 1;
int main(){scanf("%d",&t);while(t--){ll n,sum = 0;scanf("%lld",&n);for(ll l=1,r;l<=n; l=r+1){r = n/(n/l);sum+=n/l*(r-l+1);}printf("Case %d: %lld\n",cnt++,sum);}return 0;
}
//对称点(sqrt(n),sqrt(n)),求一半面积乘2//分块数论:https://blog.csdn.net/weixin_43627118/article/details/104024380?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight
8.Pairs Forming LCM
1.题意
在a,b中(a,b<=n),有多少组(a,b) (a<b)满足lcm(a,b)==n;
2.思路
素因子分解:n = p1 ^ e1 * p2 ^ e2 *…*pn ^ en
取n的两个因子a,b
a=p1 ^ a1 * p2 ^ a2 *…*pn ^ an
b=p1 ^ b1 * p2 ^ b2 *…*pn ^ bn
**gcd(a,b)=p1 ^ min(a1,b1) * p2 ^ min(a2,b2) *…*pn ^ min(an,bn)
lcm(a,b)=p1 ^ max(a1,b1) * p2 ^ max(a2,b2) …pn ^ max(an,bn)
分解n,n = p1 ^ e1 * p2 ^ e2 *…*pk ^ ek,
lcm(a,b)=p1 ^ max(a1,b1) * p2 ^ max(a2,b2) *…*pk ^ max(ak,bk)
所以,当lcm(a,b)==n时,max(a1,b1)==e1,max(a2,b2)==e2,…max(ak,bk)==ek
当ai == ei时,bi可取 [0, ei] 中的所有数 有 ei+1 种情况,bi==ei时同理。
那么就有2(ei+1)种取法,但是当ai = bi = ei 时有重复,所以取法数为2(ei+1)-1=2ei+1。
除了 (n, n) 所有的情况都出现了两次 那么满足a<=b的有 (2ei + 1)) / 2 + 1 个,+1的情况是a = b的时候
参考dl
3.代码
#include <bits/stdc++.h>
using namespace std;
int k;
long long suv[100500];
const int N=10000100;
long long prime[N/10]={0};
int num_prime=0;
bool isNotPrime[N]={1,1};
void su(){for(long i = 2 ; i < N ; i ++){if(!isNotPrime[i])prime[num_prime++]=i;for(long j = 0 ; j < num_prime &&i*prime[j]<N ;j ++) {isNotPrime[i * prime[j]] = 1;if( !(i % prime[j]))break;}}
}
void prime_solve(long long n){memset(suv,0,sizeof(suv));for(long long i=0;i<num_prime&&prime[i]*prime[i]<=n;i++){// cout<<prime[i]<<endl;if(n%prime[i]==0){while(n%prime[i]==0){n/=prime[i];suv[k]++;}//cout<<prime[i]<<" "<<suv[k]<<endl;k++;}}if(n!=1)suv[k++]=1;
}//用这种分解方法比较快int main(){int t;scanf("%d",&t);int m=1;su();while(t--){long long n;scanf("%lld",&n);k=0;prime_solve(n);long long sum=1;for(int i=0;i<k;i++)sum*=(2*suv[i]+1);printf("Case %d: %lld\n",m++,(sum+1)/2);}return 0;
}
//https://blog.csdn.net/acvay/article/details/47333871
9.Harmonic Number
1.题意
输入n,求调和级数
2.思路
结论题。
当n很小的时候,前缀和预处理,O(1)访问
当n很大的时候,调和级数的近似和为:f(n)=ln(n)+C+1/(2*n);
C为欧拉常数
C = 0.57721566490153286060651209
3.代码
#include"iostream"
#include"cmath"
#include"cstdio"
using namespace std;
const int N = 100005;
const double r = 0.57721566490153286060651209;//欧拉常数
double a[N];
int main(){for(int i = 1; i <= N; ++i)a[i] = a[i-1] + 1.0/i;int t, cnt = 0;cin >> t;while(t--){int n;cin >> n;if(n <= N) printf("Case %d: %.10f\n",++cnt, a[n]);else printf("Case %d: %.10f\n",++cnt, log(n) + r + 1.0/(2*n));}return 0;
}
10.Mysterious Bacteria
1.题意
x=b^p 给出x求出最小的p
2.思路
开始想两层循环暴力跑,底数从1~2^16(65536),幂从1到32,后来发现不对,大于1e7的样例就跑不出来了。
后来又想用唯一分解定理写,以为要求最大的pi,发现还是不对
补充知识:任何一个数都可以分解成如下形式:x = p1x1*p2x2*p3x3*…*psxs,pi为质数
比如:24 = 2^3 * 3^1
但这里答案并不是3,因为题目要求最后的底数就一个b,所以需要能合并。
再如:324 = 3^4 * 2^2,发现p应该是gcd(4, 2) = 2,即324 = 18^2
因此得出p=gcd(x1,x2,x3,x4…,xk)
还有一个坑点就是n可以是负数,此时需要转化为正数来求。
如果p是偶数,需要做修正,因为-16 != -2^4,所以,需要除2使其变成奇数,比如-324 = -(18^2) = -324^1
如果p是奇数,一个数的奇数次幂可以是负数,则不需要调整。
参考网友
3.代码
错误代码
#include"iostream"
#include"cmath"
#include"cstdio"
using namespace std;
typedef long long LL;
const int N = 65536;
int main(){int t, cnt = 0;cin >> t;while(t--){LL n;cin >> n;bool f = 0;for(int i = 1; i <= N; ++i){LL p = 1;for(int j = 1; j <= 32; ++j){p*=i;if( p == n) {printf("Case %d: %d\n",++cnt, j);f = 1;break;}}if(f) break;}}return 0;
}
AC代码
#include"iostream"
#include"cmath"
#include"cstdio"
using namespace std;
typedef long long LL;
const int N = 1e5+10;
int prime[N],cnt;
bool st[N];
LL gcd(LL a, LL b)
{return b ? gcd(b, a % b) : a;
}
void Prime(int n){ //线性筛for(int i = 2; i <= n; ++i){if(!st[i]) prime[ cnt ++] = i;for(int j = 0; prime[j] <= n/i; ++j){st[prime[j] * i] = 1;if(i % prime[j] == 0) break;}}
}
int main(){Prime(N);int t, c = 0;cin >> t;while(t--){LL n;bool f= 0; //标记n的正负cin >> n;if(n < 0) n = -n, f = 1; //n是负数,标记一下,后面做修正int p = 0;for(LL i = 0; prime[i] <= n/prime[i]; ++i){ //素数分解定理if(n % prime[i] ==0){LL s = 0;while(n %prime[i] == 0){n/=prime[i];s++;}if(p == 0) p = s;else p = gcd(p, s);}}if(n > 1) p = gcd(p, 1);if(f) while( p%2 == 0) p >>= 1; //如果n是负数,那么p只能是奇数,因为一个数的偶次幂必然是正数,所以作除2操作将其变成奇数printf("Case %d: %lld\n",++c, p);}return 0;
}
11.Large Division
1.题意
大数取余
2.思路
大数除法模板题
3.代码
#include"iostream"
#include"cmath"
#include"cstdio"
#include"unordered_map"
#include"vector"
using namespace std;
typedef long long LL;
// A / b = C ... r, A >= 0, b > 0
int main(){int t, c = 0;scanf("%d",&t);while(t--){string a;LL b,r;cin >> a >> b;if(b < 0) b = -b;vector<int>A;for(int i = a.size()-1; i >=0 ; --i) if(a[i] == '-') continue;else A.push_back(a[i]-'0');vector<int> C;int r = 0;for (int i = A.size() - 1; i >= 0; i -- ){r = r * 10 + A[i];C.push_back(r / b);r %= b;}if(r == 0)printf("Case %d: divisible\n",++c);elseprintf("Case %d: not divisible\n",++c);}return 0;
}
Python直接写
# Python代码
t = int(input())
c = 1
while t:if t == 0:breaka, b = map(int, input().split())if a % b == 0:print("Case " + str(c) + ": divisible")else:print(print("Case " + str(c) + ": not divisible"))t = t - 1c = c + 1
12.Fantasy of a Summation
1.题意
优化题目中的代码,题目中复杂度为n^k
2.思路
找规律,写几组样例即可发现一共有kn^k个数,而且每个数出现的次数是一样的,那么每个数出现的次数就是kn ^(k-1),那么答案:ans =∑(i从1到n) a[i] * k * n ^(k-1) = sum * k * n ^(k-1); 用快速幂求即可。
3.代码
#include"iostream"
using namespace std;
typedef long long LL;
int cnt = 0;
LL qp(LL a, LL b, LL p){LL res = 1;while(b){if( b&1 ) res = res * a %p;b>>=1;a = a * a % p;}return res;
}
int main(){int t;cin >> t;while(t--){LL n, k, p;scanf("%lld%lld%lld", &n, &k, &p);LL sum = 0;for(int i = 1; i <= n; ++i){LL x; scanf("%lld",&x);sum += x;sum %= p;}sum = (sum * k) % p * qp(n,k-1, p) % p;printf("Case %d: %lld\n",++cnt,sum);}return 0;
}
13.Help Hanzo
1.题意
求a到b的素数的个数
2.思路
二次筛法
这里的区间范围给定的最大值是2^31 - 1,而用线性筛法求的是[1,n]中的所有质数,因此直接用线性筛法求肯定会直接gg,因此需要通过挖掘某些性质,才能有技巧性的完成。
参考来源
注意点:
1.筛[a,b]之间的素数时,要从第一个大于a并且是素数倍数的数开始,当a,b比较小的时候,可能[a,b]中包含素数p,因此:max((a+p-1)/p * p, 2*p)
2.需要注意偏移量,因为b-a<=1e5,那么s标记数st开到1e5就可以(我们这里开到1e6是因为要筛出2^16以内的素数),如果不做偏移量修正,那么可能需要访问到st[1e9],显然数组开不到这么大。
3.代码
#include "iostream"
#include "cmath"
#include "cstring"
using namespace std;
typedef long long LL;
const int N = 1000010;
int c = 0;
int prime[N],cnt;
bool st[N];void Prime(int n){memset(st, 0 ,sizeof st);cnt = 0;for(int i = 2; i<= n; ++i){if(!st[i]) prime[cnt ++] = i;for(int j = 0; prime[j] <= n/i; ++j){st[prime[j] * i] = 1;if( i % prime[j] == 0) break;}}
}
int main(){Prime(N);int t;scanf("%d",&t);while(t--){memset(st, 0, sizeof st);LL a,b;scanf("%lld%lld", &a, &b);for(int i = 0; i < cnt; ++i){int p = prime[i];//筛去[a,b]的合数for(LL j = max((a+p-1)/p*p, 2ll*p); j <= b; j+=p) st[j - a] = 1;}cnt = 0;for(int i = 0; i <= b-a; ++i)if(i+a > 1 && !st[i]) ++cnt;printf("Case %d: %d\n", ++c, cnt);}return 0;
}
14.Trailing Zeroes (III)
1.题意
输入q,代表N!末尾有q个0,求出最小的N
2.思路
打表到20!发现:
0-4:末尾无0
5-9:末尾1个0
10-14:末尾2个0
15-19:末尾3个0
…
猜测N每+5,末尾就多1个0
但是这样显然求不到q = 1e8时的N
重新思考:
N!末尾的0一定是由2*5产生的。
而且2因子的个数一定比5因子的个数多。
所以只需要求N!的5因子的个数。
用到了一个数论知识:
若p是质数,p<=n,则n!是p的倍数,设p^x是p在n!内的最高幂,则
x=[n/p]+[n/p^2]+ [n/p^3]+…;
而且[n/(ab)]=[[n/a]/b]
参考来源
3.代码
#include"iostream"
using namespace std;
int c;
const int N = 5e8;
int find(int x){int sum = 0;while(x){sum += x/5;x/=5; } return sum;
}
int check(int x){int l=1,r=N;while(l <= r){int mid = (l+r) >>1;int t = find(mid);if(t < x) l = mid + 1;else if(t > x) r = mid - 1;else return mid; }return -1;
}
int main(){int t;scanf("%d", &t);while(t--){int x;scanf("%d", &x);printf("Case %d: ",++c);int p = check(x);if(p==-1) puts("impossible");else printf("%d\n",p-p%5); //求出最小的满足条件的N,比如这里q=1时,求出的答案是7,需要ans-ans%5 } return 0;
}
15.GCD - Extreme (II)
1.题意
找出一个数的阶乘的末尾0个数是q
2.思路
3.代码
16.Code Feat
1.题意
2.思路
3.代码
17.Emoogle Grid
1.题意
2.思路
3.代码
18.青蛙的约会
1.题意
青蛙A,B在一条环形线上,抽象成数轴,长度为l,起始坐标分别为x、y,单位跳跃距离分别为n,m,问最少走几次l能相遇,若不能相遇输出impossible
2.思路
参考来源
3.代码
#include<cstdio>
#define LL long long
LL x,y,m,n,l,a,b,c,x0,y0,g,tmp;
void exgcd(LL a,LL b){if(!b){x0=1;g=a;return;}//顺便求gcdexgcd(b,a%b);tmp=x0;x0=y0;y0=tmp-a/b*y0;
}
int main(){scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&l);a=n-m;b=l;c=x-y;if(a<0)a=-a,c=-c;//处理a为负数情况exgcd(a,b);if(c%g)puts("Impossible");else printf("%lld\n",(c/g*x0%(b/g)+b/g)%(b/g));//求最小非负整数解return 0;
}
19.C Looooops
1.题意
求a+bx≡c(mod 2^k)
2.思路
题目的意思就是 a+bx≡c(mod 2^k)
典型的线性同余方程 转化为 bx-y2^k=c-a 当gcd(b,2^k)能整除c-a的时候 就存在解
通解好求 跑一边exgcd可以得出x0 然后 基础解 x=(c-a)/gcd(b,2^k)x0; 通解为 x0+zz(2^ k/gcd(2^k,b); 显然当zz=0的时候最小
关键是要求出最小正整数解。
对于ax+by=gcd(a,b) 这个方程 我们有通解 x=x0+b/gcd(a,b);
那么怎么求x的最小正整数解。呢 首先知道一点 b/gcd(a,b)是解的最小区间
这个怎么理解呢
假设c为x的解的最小间距,此时d为y的解的间距,所以x=x0+ct,y=y0-d*t(x0,y0为一组特解,t为任意整数)
带入方程得:a*x0+a*c*t+b*y0-b*d*t=n,因为a*x0+b*y0=n,所以a*c*t-b*d*t=0,t不等于0时,a*c=b*d因为a,b,c,d都为正整数,所以用最小的c,d,使得等式成立,ac,bd就应该等于a,b的最小公倍数a*b/gcd(a,b),所以c=b/gcd(a,b),d就等于a/gcd(a,b)。
所以,若最后所求解要求x为最小整数,那么x=(x0%(b/gcd(a,b))+b/gcd(a,b))%(b/gcd(a,b))即为x的最小整数解。
x0%(b/gcd(a,b))使解落到区间-b/gcd(a,b) ~ b/gcd(a,b),再加上b/gcd(a,b)使解在区间0~2*b/gcd(a,b),
再模上b/gcd(a,b),则得到最小整数解
参考链接
3.代码
#include "iostream"
#include "cstdio"
using namespace std;
typedef long long LL;
LL a,b,c,k;LL exgcd(LL a,LL b, LL &x,LL &y){if(!b){x = 1,y = 0;return a;}LL d = exgcd(b, a%b, y, x);y -= a/b*x;return d;
}
int main(){while(scanf("%lld%lld%lld%lld",&a,&b,&c,&k),a+b+c+k){LL x,y;LL p = b-a;LL z = 1ll << k;LL d = exgcd(c,z,x,y);if(p%d) puts("FOREVER");else{LL t = z/d;x = (x*(p/d)%t+t)%t;printf("%lld\n",x);}}return 0;
}
20.Death to Binary?
1.题意
2.思路
3.代码
21.Primes
1.题意
1-16000,是素数输出yes,否则no
2.思路
素数筛筛一遍1-16000
注意1,2要输出no,n<=则结束输出
3.代码
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 20010;
int c=0;
int prime[N],cnt;
bool st[N];
void Prime(int n){st[1] = 1;for(int i = 2; i <= n; ++i){if(!st[i]) prime[cnt ++] = i;for(int j = 0; prime[j] <= n/i;++j){st[prime[j] * i] = 1;if( i % prime[j] ==0) break;}}st[2]=1;
}
int main()
{Prime(N);int n;while(cin >> n&&n>0) {printf("%d: ",++c);if(st[n]) puts("no");else puts("yes");}return 0;
}
22.Maximum GCD
1.题意
n个数中选2个,求gcd,找出最大的gcd
2.思路
暴力跑
输入很花哨,用getline
3.代码
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int n,num,a[110];
string s;
int gcd(int a,int b)
{return b?gcd(b, a%b):a;
}
int main()
{cin>>n;getchar();while(n--){num=0;getline(cin,s);stringstream ss(s);while(ss>>a[num]) num++; //控制读入int ans=0;for(int i=0;i<num;i++)for(int j=i+1;j<num;j++)ans=max(ans,gcd(a[i],a[j]));cout<<ans<<endl;}return 0;
}
23.Prime Time
1.题意
对于fn = n^2+ n + 41,n属于[l,r],求素数的概率
2.思路
跑一下就可
这题结果要加1e-8
前缀和打表,否则超时
3.代码
#include "iostream"
#include "cstdio"
using namespace std;
const int N = 100010;
int sum[N];
bool isPrime(int n){for(int i = 2; i <= n/i; ++i)if(n%i==0) return 0;return 1;
}
void init(){int num;for(int i = 0; i < N; ++i){int f = i*i+i+41;if(isPrime(f)) num++;sum[i] = num;}
}
int main(){int l,r;double ans;init();while(~scanf("%d%d",&l,&r)){if(l==0) ans = 100.00*sum[r]/(r-l+1);else ans = 100.00*(sum[r]-sum[l-1])/(r-l+1);printf("%.2f\n",(double)ans+1e-8);}return 0;
}
24.The equation
1.题意
线性方程区间求解的个数
2.思路
参考
3.代码
#include"bits/stdc++.h"
using namespace std;
typedef long long LL:
LL a,b,c,x1,x2,y1,y2,x,y;
inline long long cmin(const long long &x,const long long &y) {return x<y?x:y;}
inline long long cmax(const long long &x,const long long &y) {return x>y?x:y;}
void exgcd(LL a,LL b)
{if (!b){x = 1;y = 0;return;}LL d = exgcd(b, a%b, y, x);y -= a/b*x;return d;
}
int main()
{cin >> a >> b >> c >> x1 >> x2 >> y1 >> y2;c=-c;if (c<0) {a = -a, b =- b, c =- c;if (a<0) {a =- a; LL t = x1;x1 = -x2; x2 = -t;}if (b<0) {b = -b;LL t = y1; y1 = -y2; y2 = -t;}if (a == 0 && b == 0){if (c == 0){cout << (x2-x1+1)*(y2-y1+1) <<endl;return 0;}else cout <<0<<endl; return 0;}else if (a == 0){if (c%b == 0)if (c/b<=y2 && c/b>=yy1) cout << x2-x1+1 <<endl;else cout << 0 << endl;return 0;}else if (b == 0){if (c%a == 0)if (c/a <= x2 && c/a >= x1) cout << y2-y1+1 << endl;else printf("0");return 0;}long long d=gcd(a,b);if (c%d!=0){printf("0");return 0;}a=a/d;b=b/d;c=c/d;exgcd(a,b);x0=x0*c;yy0=yy0*c;double tx2=x2,tx1=x1,tx0=x0,ta=a,tb=b,tc=c,ty1=yy1,ty2=y2,ty0=yy0;long long down1=floor(((tx2-tx0)/tb)),down2=floor(((ty0-ty1)/ta));long long r=cmin(down1,down2);long long up1=ceil(((tx1-tx0)/tb)),up2=ceil(((ty0-ty2)/ta));long long l=cmax(up1,up2);if (r<l) printf("0");else printf("%I64d",r-l+1);return 0;}
25.Farey Sequence
1.题意
欧拉函数模板题
2.思路
素数筛+欧拉函数+前缀和
3.代码
#include "iostream"
using namespace std;
typedef long long LL;
const int N = 1e6+10;
int prime[N],cnt;
LL phi[N];
bool st[N];
void eluer(int n){phi[1] = 1;for(int i = 2; i <= n; ++i){if(!st[i]) {prime[cnt ++] = i;phi[i] = i-1;}for(int j = 0; prime[j] <= n/i; ++j){st[prime[j] * i] = 1;if(i % prime[j] == 0) {phi[prime[j] * i] = prime[j]*phi[i];break;}else phi[prime[j] * i] = (prime[j]-1)*phi[i];}}
}
int main(){int n;eluer(N);for(int i = 3; i <= N; ++i) phi[i]+=phi[i-1];while(cin>>n,n){cout << phi[n] << endl;}return 0;
}
26.The Super Powers
1.题意
输出所有可以表示成a^b 或者(a^ b)^c的数
比如:
16 = 2^4= 4^2
64 = 8^2 = 2^6
2.思路
最大到2^64-1暴力找肯定超时
可以想到, 如果a^b可以拆分, 那么b一定是个合数
如此看来幂的范围是:[4 - 64)
底数范围:[2, 2^16)
a的最大次幂:b = loga(2^64-1) = log(2^64-1) / log(i);
求的过程中会有重复的,用set存即可去重
3.代码
#include "iostream"
#include "set"
#include "cmath"
using namespace std;
typedef unsigned long long LL;
const int N = 1<<16;
set<LL>se;
const int index[50] =
{4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 22, 24, 25, 26,27, 28, 30, 32, 33, 34, 35, 36, 38, 39, 40, 42, 44, 45, 46,48, 49, 50, 51, 52, 54, 55, 56, 57, 58, 60, 62, 63, 64 /// 多算一个
};///合数表
int main(){se.insert(1);LL x=1;for(int i = 2; i < N; ++i){x=(LL)i*i;x*=x;se.insert(x);int t = ceil(64 * log(2) / log(i)) - 1;for(int j = 1; index[j] <= t; ++j){x*=(index[j]-index[j-1]==2)?i*i:i;se.insert(x);}}for(auto s : se)cout << s<<endl;return 0;
}
【ACM】kuangbin基础数论专题相关推荐
- ACM数论专题3——素数(质数)
ACM数论专题3--素数 素数是什么 蛮力算法求素数 蛮力算法的实现以及分析 时间复杂度 蛮力算法的改进 时间复杂度 **埃筛** 时间复杂度 线筛 线筛原理分析 线筛实现 素数是什么 质数1 (pr ...
- 数学/数论专题-学习笔记:狄利克雷卷积
数学/数论专题-学习笔记:狄利克雷卷积 1. 前言 2. 一些基础函数 3. 积性函数 4. 狄利克雷卷积 5. 总结 6. 参考资料 1. 前言 狄利克雷卷积,是学习与继续探究 μ\muμ 函数和 ...
- 数论专题(一)数论基本概念
努力努力再努力x 努力努力再努力x 博客园 首页 新随笔 联系 订阅 管理 数论专题(一)数论基本概念 转载自:https://blog.csdn.net/whereisherofrom/articl ...
- 数学/数论专题:莫比乌斯函数与欧拉函数
数学/数论专题:莫比乌斯函数与欧拉函数(进阶) 0. 前言 1. 前置知识 2. 正文 3. 总结 4. 参考资料 0. 前言 本篇文章会从狄利克雷卷积的角度,讨论莫比乌斯函数与欧拉函数的相关性质. ...
- 算法之基础数论应用篇(一)
基础数论应用篇 子集和 题目描述 筛质数 筛质数模板 欧拉筛 线性筛 哥德巴赫猜想 夏洛克和他的女朋友 二次筛法 分解质因数 试除法分解质因数 分解阶乘质因子 快速幂 模板 快速幂 快速乘法 序列的第 ...
- nssl1174-阶乘【!基础!数论】
前言 比赛时xjq说这道题很水,是个基础数论. 然后- 就连交都没交 正题 给出n个数,求一个最小的mmm使得 m!∏i=1nai=q(q∈N+)\frac{m!}{\prod_{i=1}^na_i} ...
- 计算机内存知识txt,计算机内存基础知识专题
计算机内存基础知识专题 计算机是由哪几部分组成的呢?简单的说,一个完整的计算机系统是由软件和硬件组成的.其中,硬件部分由中央处理单元(运算器和控制器).存储器和输入/输出设备构成.这次我们要谈的是存储 ...
- 数学/基础数论——从LeetCode题海中总结常见套路
今天是大年初一,祝大家新年快乐! 目录 基础数论求质数:LeetCode204.计数质数 常规解法: 娱乐一下:偷鸡式解法 埃拉托色尼筛选法 统计5因子的个数:LeetCode172.阶乘后的零 暴力 ...
- 【数论】基础数论概念
基础数论概念 首先我们来回顾一下基础数论中关于整数集Z={-,-2,-1,0,1,2,-}和自然数集N={0,1,2,3,4,-}的一些概念. 整除性与约数 一个整数可以被另一个整数整除是数论中的一个 ...
最新文章
- YoloV5代码详细解读
- 改进 网站资源探测工具(添加代理)
- webService学习3:客户端生成webservice代码
- 微信小程序小结(3) -- 使用wxParse解析html及多数据循环
- 固执己见的框架(例如Spring Boot)的危险。 求知代码反转
- PHPCMS 模板的设置
- 今日头条ocpm计费规则_入门篇|信息流广告的游戏规则—竞价机制
- Android第四十五天
- 蟒蛇语言和python_蛇、蟒、蚺、蝰有什么区别
- win2003server域控服务器安装及设置
- trunk端口_超全!华为交换机端口vlan详解~
- 【转】TCP状态变迁图
- protocal buffer repeate 关键字
- PIPIOJ1099PIPI的油田
- Arduino + SmartAirFilter 制作智能感应的 PM 空气净化器
- PRML读书会第一章 Introduction(机器学习基本概念、学习理论、模型选择、维灾等)...
- 分级阅读网站/阅读网站.阅读系统的设计与实现
- 过敏体质也会遗传给孩子,孕期妈妈应该尽早预防
- 计算机音乐锦鲤抄,锦鲤抄 MIDI File Download :: MidiShow
- Django计算机毕业设计JAVA高校田径运动会管理python(源码程序+lw+远程部署)