24暑假集训day3下午

实现代码:

int exgcd(int a,int b, int &x, int &y){
	if(b == 0){
		x = 1;
		y = 0;
		return a;
	}
	int d = exgcd(b, a % b, x, y);
	int k = x;
	x = y;
	y = k - (a / b) * y;
	return d;
}
int main(){
	int a = read(), b = read();
	int x, y;
	int d = exgcd(a, b, x, y);
	cout << d << " " << x << " " << y << '\n';
	return 0;
}


#define ll long long 
ll fac[N], ifac[N];
const ll p=998244353;
ll power(ll a, ll b){
	ll ret = 1;
	while (b){
		if(b & 1){
			ret = ret * a % p;
		}
		a = a * a % p;
		b >>= 1;
	}
	return ret;
}
ll c(int a, int b){
	if(a < b || b < 0){
		return 0;
	}
	return fac[a] * ifac[b] % p * ifac[a - b]% p;
}
void initialize(){
	fac[0]= 1;
	for(int i=1; i < N; i++){
		fac[i] = fac[i - 1] * i % p;
	}
	ifac[N - 1] = power(fac[N - 1], p - 2);
	for(int i = N - 2;i >= 0;i--){
		ifac[i]= ifac[i + 1] * (i + 1) % p;
	}
}

小凯的数字

思路:

我们知道 𝑥𝑥的"数位和" (mod9)

所以 𝑙(𝑙+1)(𝑙+2)r𝑙的"数位和"+(𝑙+1)的"数位和"++𝑟的"数位和"𝑙+(𝑙+1)++𝑟(mod9)

问题变为计算 (𝑙+𝑟)(𝑟𝑙+1)2/2 可以变为 ×5

std:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<map>
#include<vector>
#include<queue>
#include<set>
#include<unordered_map>
#include<bitset>
#define int long long
using namespace std;
const int MAXN=100005;

inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while (ch<'0'||ch>'9'){
		  if (ch=='-') f=-1;
		  ch=getchar();
	}
	while (ch>='0'&&ch<='9'){
		  x=x*10+ch-48;
		  ch=getchar();
	}
	return x*f;
}
signed main(){
	int q;
	long long ans;
	q=read();
	while(q--){
		int l,r;
		l=read();
		r=read();
		ans=(l+r)%9*(r-l+1)%9*5%9;
		cout<<ans<<'\n';
	}
	return 0;
}

中国剩余定理

给定一些 xa𝑖(modmi) 的限制,求 x。保证 mi 两两互质。
我们只需要每次合并两个方程。

现在考虑

{xa1(modm1)xa2(modm2)

{a1+m1k1=xa2+m2k2=x

代入得

m1k1m2k2=a2a1

。使用扩展欧几里得算法计算出 k1,k2(由于 gcd(m1,m2)=1,则一定有解),然后代回得到 x 的一个特解 x0

将两个方程合并为一个新的方程 xx0(modm1m2)

实际上 k1=(a2a1)m1(1),其中 m1(1) 表示 m1modm2 下的逆元。


小凯的疑惑

思路:

𝑀 无法被支付,则 𝑎𝑥+𝑏𝑦=𝑀 没有自然数解。

假设 𝑎𝑥0+𝑏𝑦0=𝑀 是一组特解,如果𝑥0,𝑦0 其中有负数(不妨设 𝑦0<0),就需要让 𝑥0 帮他匀一点,匀到 0 为止。

具体地,设𝑥0=𝑘𝑏+𝑟 (0𝑟<𝑏) ,那么𝑎𝑟+𝑏(𝑦0+𝑘𝑎)=𝑀 是最极限的情况。因为 𝑥0 这一边也需要 ≥0 。

如果此时𝑦0+𝑘𝑎 仍然 <0 ,就说明无解。可知 𝑦0+𝑘𝑎=1,𝑟=𝑏1𝑀 最大为 𝑎(𝑏1)𝑏=𝑎𝑏𝑎𝑏

质数筛

素数判断的方法

  1. 既然第一种方法时间复杂度太大,那么我们要考虑一种新的方式。首先给出这种方法的名字——埃式筛。听上去是不是一个很高大上的名字,但其实原理很简单,我们用一个数组来存放n以内的所有质数,我们要用到一个布尔数组来标记n以内的所有不是质数的数(也要标记1,1既不是质数也不是合数)。再标记此质数所有的倍数(因为质数所有的倍数都不是质数)。最后输出所有质数

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
bool is[10005];
int prim[10005];
int cnt=0;
void Aprime(int n){
   is[1]=1;//1既不是质数也不是合数 
   for(int i=2;i<=n;i++){//遍历2~n之间的所有整数 
   	if(is[i]==0){//如果没有被标记过,说明是质数 
   		prim[++cnt]=i;//存储质数 
   		for(int j=i*2;j<=n;j+=i){//标记所有此质数的倍数 
   			is[j]=1;
   		}
   	}
   }
}
int main(){
   int n;
   cin>>n;
   Aprime(n);//调用函数 
   for(int i=1;i<=cnt;i++){
   	cout<<prim[i]<<"\n";//输出质数 
   }
   return 0;
}

素数判断的方法2:

埃式筛的缺点在于有和数被重复标记了多次,所以还不是最优解,这里奉上更快的办法——欧拉筛。欧拉筛,也叫线性筛,是更快的判断质数的方法。其思路在埃式筛的基础上有所改进,让质数库里的每个质数分别与循环中的i相乘,如果i取余这个质数等于0,则直接跳出循环,避免重复标记,节省时间。

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
bool is[10005];
int prim[10005];
int cnt=0;
void Aprime(int n){
	is[1]=1;//1既不是质数也不是合数 
	for(int i=2;i<=n;i++){
		if(is[i]==0){//如果没有被标记过,说明是质数
			prim[++cnt]=i;//存储质数
		}
		for(int j=1;j<=cnt&&i*prim[j]<=n;j++){//质数不超过n 
			is[i*prim[j]]=1;//用新数去乘每一个质数 
			if(i%prim[j]==0){
				break;//不重复标记,取余等于0就跳出循环 
			}
		}
	}
}
int main(){
	int n;
	cin>>n;
	Aprime(n);//调用函数 
	for(int i=1;i<=cnt;i++){
		cout<<prim[i]<<"\n";//输出质数 
	}
	return 0;
}

选数

思路:
由于本题数据较水,对每个子集和暴力试除就能过。

但如果数据不水,需要使用线性筛,并且要压一下空间。

std:

#include<bits/stdc++.h>
using namespace std;
bool isprime(int a){
    for(int i=2;i*i<=a;i++)if(a%i==0)return 0;
    return 1;
}
long long ans,a[25],n,k;
void dfs(int m, int sum, int s){
    if(m == k){
        if(isprime(sum))ans++;
        return ;
    }
    for(int i = s; i<n;i++)dfs(m+1,sum+a[i],i+1);
    return ;
}

int main(){
    scanf("%d%d",&n,&k);
    for(int i = 0; i < n; i++)scanf("%d",&a[i]);
    dfs(0, 0, 0);
    printf("%d\n",ans);
    return 0;
}

选素数

思路:
假设一开始是 𝑥 ,操作一次变为 𝑚 ,操作两次变为 𝑛 。

第一次操作选的 𝑝1 需要满足 𝑚𝑝1<𝑥𝑚。所以对于一个固定的 𝑚 ,最小的可行 𝑥=minp|nminnp<mnf(m) 。设 𝑓(𝑚)=𝑚𝑝𝑚𝑎𝑥+1

第二次操作选的 𝑝2 需要满足 𝑛𝑝2<𝑚𝑛。我们需要找一个 𝑓 最小的 𝑚,即答案为minp|nminnp<mnf(m)

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<map>
#include<vector>
#include<queue>
#include<set>
#include<unordered_map>
#include <climits>

#define ll long long

using namespace std;

const int MAXN = 1000010;
const int N = 1000000;

int n;
bool b[MAXN];
int prime[MAXN], idx;
int f[MAXN];
int ans = INT_MAX;

inline int get(int x){
	if (!b[x]) return INT_MAX;
	return x - f[x] + 1;
}

int main(){
	scanf("%d", &n);
	for (int i = 2; i <= N; ++i){
		if (!b[i]) prime[++idx] = f[i] = i;
		for (int j = 1; j <= idx && (ll) i * prime[j] <= N; ++j){
			b[i * prime[j]] = true;
			f[i * prime[j]] = max(f[i], prime[j]);
			if (i % prime[j] == 0) break;
		}
	}
	for (int i = get(n); i <= n; ++i)
		ans = min(ans, get(i));
	if (ans == INT_MAX) puts("-1");
	else printf("%d\n", ans);
	return 0;
}


数列之异或

思路:

2𝑘(2𝑘+1)=1

所以 𝑁 为奇数时

123𝑁=1(23)(𝑁1𝑁)=111={0,N121,N12

𝑁 为偶数时,令计算 𝑁1 的答案,再异或上 𝑁

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<map>
#include<vector>
#include<queue>
#include<set>
#include<unordered_map>
#include<bitset>
#define int long long
using namespace std;
const int MAXN=100005;
inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while (ch<'0'||ch>'9'){
		  if (ch=='-') f=-1;
		  ch=getchar();
	}
	while (ch>='0'&&ch<='9'){
		  x=x*10+ch-48;
		  ch=getchar();
	}
	return x*f;
}
signed main(){
	int n;
	n=read();
	if(n%2!=0){
		if(((n-1)/2)%2!=0){
			cout<<0;
		}else{
			cout<<1;
		}
	}else{
		if(((n-1)/2)%2!=0){
			cout<<(0^n);
		}else{
			cout<<(1^n);
		}
	}
	return 0;
}

posted @   Yantai_YZY  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示