蓝桥杯算法入门23 ( 数论 - 十一届真题)


#include
using namespace std;

简单数论

整除 - 分解质因数
质数
积性函数
模算术
例题

公约数-公倍数-唯一分解定理

最大公约数:
显然 gcd(a,b) == gcd(b,a) 性质: gcd(a,b) = gcd(b,a-b) = gcd(b,a mod b);
gcd(a,b) = 1时 a,b互质
最小公倍数:
显然lcm(a,b) = lcm(b,a)
lcm(a,b) = a * b / gcd(a,b) = a / gcd(a,b) * b 先除再乘防止数值爆炸!!!
质数:设 n >= 2 ,所有满足 [1,n]的数不是n的约数,则称n为质数 ,否则称n为合数
唯一分解定理(分解质因数):设 n >= 2 ,n = ∏(i = 1 --> m) p[i]k[i] (p[1 --> m]为质数)

质因数分解

#include<vector>
//质因数分解
vector<int> factor(int n) {
	vector<int> f;
	for(int i = 2; i * i <= n; i++) {
		while(n % i == 0) { //是质数且能整除n ,每个因数还可以多除几次直到不能整除
			f.push_back(i);
			n /= i; //注意到n会变小,如果n小于i*i,n剩下的最后肯定是一个质数,也要存入
		}
	}
	if(n > 1) { //存最后的数 , f中 所有数相乘 = = n
		f.push_back(n);
	}
	return f;
}

int test_01() {
	int n;
	cin >> n;
	for(int i = 0; i < factor(n).size(); i++) {
		cout << factor(n)[i] << endl;
	}

	return 0;
}

解法三 : p质数存表,枚举质数n%p[i]
vector p;
vector factor2(int n) {
bool flag = true;
for(int i = 2; i<= 100; i++) {
for(int j = 2; j * j <= i ;j++) {
if(i % j == 0) {
flag = false;
break;
}
}
if(flag) {
p.push_back(i);
}
flag = true;//恢复
}
vector f;
for(int i = 0; i < p.size(); i++) {
if(p[i] * p[i] > n) {
break;
}
while(n % p[i] == 0) {
f.push_back(p[i]);
n /= p[i];
}
}
if(n > 1) {
f.push_back(n);
}
return f;
}

/*欧拉质数筛法 --i * p[j]的质因子一定小于p[j],如果枚举到i,若i没有被标记,则i为质数
const int N = 100000;
bool vis[N + 1];
vector p;
void sieve() {
for(int i = 2; i <= N; i++) {
if(!vis[i]) {
p.push_back(i);
}
for(int j = 0; i * p[j] <= N + 1; j++) {
vis[i * p[j]] = 1;
if(i % p[j] == 0) {
break;
}
}
}
break;
}
*/
/积性函数
如果f(1) = 1 ,且对于a,b互质 , f(a
b) = f(a) * f(b)
欧拉 φ函数 ,约数函数
模乘法的逆元 (密码学嘿嘿)
a * b mod n = 1 ,则称b为a模n的逆元 记为a-1
当且仅当gcd(a,n) = 1 时 (a,n互质时) ,a模n的逆元才存在!!!
b1,b2为a的逆元,则必有b1 ,与b2同模于n
费马小定理 设p为质数,a为与p互质的整数,则有 a^p - 1^ 模p 余1
欧拉定理

例题

图论
P3387 缩点 + dp

第十一届

简单序列题

1.有一个序列,序列的第一个数是n,后面的每个数是前一数整除2,请输出这个序列中值为正数的项
AcWing

#include<iostream>
#include<cstring> 

using namespace std;
typedef long long ll;

int test_02(){
	ll n;
	cin >> n;
	while(n){
		cout << n << " ";
		n /= 2;
	}
	return 0;
}

2066解码

H3el5o2 还原为 HHHellllloo

#include<iostream>
#include<cstring> 

using namespace std;

int test_03(){
	string s,res; //res存答案 
	cin >> s;
	for(int i  = 0;i < s.size();i++){ // 读入s 
		if(i + 1 < s.size() && s[i + 1] <= '9'){ //在范围内 ,且读到数字时 
			int k = s[i + 1] - '0';
			while(k--){
				res += s[i];  //字符串拼接
			}
			i++;//因为此次操作读取2位,包括了字母 + 数字位 
		}else{
			res += s[i]; //下一位不是数字,就只加一次 
		}  
	}    
	cout << res << endl; 
	return 0;
}

2067走方格 (类似数字三角形) 闫式dp分析法

左上角走到右下角 ,每次选下或右走
行号和列号都为偶数(不能走),问有多少种走法

#include<iostream> 
#include<cstring>
using namespace std;

const int N_04 = 40;
int n_04,m_04;
int f[N_04][N_04];

int test_04(){
	cin >> n_04 >> m_04;
	f[1][1] = 1;
	for(int i = 1;i <= n_04;i++){
		for(int j = 1;j <= m_04;j++){
			if(i == 1 && j == 1)continue; //为起点 
			if(i % 2 || j % 2){ //i%2 或 j%2 余 1时执行 即为奇数时执行 (等效 i,j不能同时为偶数 )   ,i,j不能都为偶数正向思维: !(i % 2 = = 0 && j % 2 == 0)
				f[i][j] = f[i - 1][j] + f[i][j - 1]; //从哪里来 ,即上一步哪些位置能走到当前位置 
			}			
		}
	}
	
	cout << f[n_04][m_04] << endl;
	return 0;
}

整数拼接 (难 * – 先跳过)
给定长度为n的数组,从中选出两个数,拼成一个新的整数
例如 12 或 345 可以拼成 12345 或 34512
注意交换A[i]与A[j]属于两种拼法,即使两者相同
计算有多少种拼法是整数k的倍数
输入:
n k [1,1e5]
A[i]…
输出:
ans
相当于 k | A[j] * 10k[i] + A[j] 等效乘10 ,再加
11个hash表A[j] * 100 … A[j]
1010

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

typedef long long LL;
const int N = 100010;
int n,m;
int a[N] , s[11][N];

int test_05(){
	scanf("%d%d",&n,&m);
	for(int i = 0;i < n;i++)scanf("%d",&a[i]);//读入数据 
	for(int i = 0;i < n;i++){//预处理hash表 
		LL t = a[i] % m; 
		for(int j = 0;j < 11;j++){
			s[j][t]++;	
			t = t * 10 % m;
		}
	}
	LL res = 0;
	for(int i = 0;i < n;i++){
		LL t = a[i] % m;
		int len = to_string(a[i]).size();
		res += s[len][(m - t) % m];
		LL r = t;
		while(len--)r = r * 10 % m;
		if(r == (m - t) % m)res--; //重复 
	}
	printf("%11d\n",res);
	return 0;
}

网络分析 (难题)
某一节点发信息会传给相邻节点,直到所有节点都直接或间接收到消息
输入
n m (节点数,操作数量)
接下来m行,每三行表示一个操作 (操作1.加一条边 2.给某个联通块中的每个点加上t)
输入:
4 8
1 1 2
2 1 10
2 3 5
1 4 1
2 2 2
1 1 2
1 2 4
2 2 1
并查集基本操作:维护连通性

#include<iostream>
#include<cstring>
#include<algorithm>

const int N = 10010;

int n,m;
int p[N],d[N];
int find(int x) {
	if(p[x] == x || p[p[x]] == p[x])return p[x];
	int r = find(p[x]);
	d[x] += d[p[x]];
	p[x] = r;
	return r;
}

int test_06() {
	scanf("%d%d",&n,&m);
	for(int i = 1; i <= n; i++)p[i] = i;
	while(m--) {
		int t,a,b;
		scanf("%d%d%d",&t,&a,&b);
		if(t == 1) {
			a = find(a),b= find(b);
			d[a] -= d[b];
			p[a] = b;
		}

		else {
			a = find(a);
			d[a] += b;
		}
		for(int i = 1; i <= n; i++) {
			if(i == find(i) )printf("%d",d[i]);
			else {
				printf("%d",d[i] + d[find(i)]);
				puts("");
			}
		}
	}
	return 0;
}



int main() {

	test_06();

	return 0;

}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值