知识补充:裴蜀定理
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)//当搜索不到的时候,如果这个数最后大于一,那么这个最后结果肯定是素数,并且指数是1
ans*=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);
else
printf("Case %d: not divisible\n",++c);
}
return 0;
}
Python直接写
# Python代码
t = int(input())
c = 1
while t:
if t == 0:
break
a, b = map(int, input().split())
if a % b == 0:
print("Case " + str(c) + ": divisible")
else:
print(print("Case " + str(c) + ": not divisible"))
t = t - 1
c = 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;}//顺便求gcd
exgcd(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;
}