[Codeforces] number theory (R1200) Part.1

[Codeforces] number theory (R1200) Part.1

题单:https://codeforces.com/problemset/page/6?tags=number%20theory,0-1200

17A. Noldbach problem

原题指路:https://codeforces.com/problemset/problem/17/A

题意 ( 2   s ) (2\ \mathrm{s}) (2 s)

给定两整数 n , k    ( 2 ≤ n ≤ 1000 , 0 ≤ k ≤ 1000 ) n,k\ \ (2\leq n\leq 1000,0\leq k\leq 1000) n,k  (2n1000,0k1000),问 [ 2 , n ] [2,n] [2,n]中是否至少有 k k k个素数能表示为三个数之和,其中两个为相邻素数,第三个为 1 1 1,若能,输出"YES";否则输出"NO".

思路

注意 n n n范围小,可先筛出 1000 1000 1000以内的素数,求出其中有多少个素数满足要求,将其数量与 k k k比较.

代码

const int MAXN = 1005;
int primes[MAXN], cnt;
bool state[MAXN];

void init() {
	for (int i = 2; i <= MAXN; i++) {
		if (!state[i]) primes[cnt++] = i;
		for (int j = 0; primes[j] <= MAXN / i; j++) {
			state[primes[j] * i] = true;
			if (i % primes[j] == 0) break;
		}
	}
}

void solve() {
	init();
	
	int n, k; cin >> n >> k;

	int ans = 0;
	for (int i = 2; i < cnt && primes[i] <= n; i++) {
		int cur = primes[i] - 1;
		for (int j = 1; j < i; j++) {
			if (primes[j] + primes[j - 1] == cur) {
				ans++;
				break;
			}
		}
	}
	cout << (ans >= k ? "YES" : "NO");
}

int main() {
	solve();
}


26A. Almost Prime

原题指路:https://codeforces.com/problemset/problem/26/A

题意 ( 2   s ) (2\ \mathrm{s}) (2 s)

称一个数是几乎素的,如果它有且只有两相异的素因子.给定一个整数 n    ( 1 ≤ n ≤ 3000 ) n\ \ (1\leq n\leq 3000) n  (1n3000),求 [ 1 , n ] [1,n] [1,n]中几乎素的数的个数.

思路

注意 n n n范围小,可先预处理出 3000 3000 3000以内几乎素的数,再二分出分界点即可.

代码

const int MAXN = 3005;
int primes[MAXN], cnt;
bool state[MAXN];
vi almost;

void dfs(int i, int product1, int j, int product2) {  // primes[i]的a次方为product1,primes[j]的b次方为product2
	if (product1 * product2 > 3000) return;

	almost.push_back(product1 * product2);
	dfs(i, product1 * primes[i], j, product2);
	dfs(i, product1, j, product2 * primes[j]);
}

void init() {
	for (int i = 2; i < MAXN; i++) {
		if (!state[i]) primes[cnt++] = i;
		for (int j = 0; primes[j] < MAXN / i; j++) {
			state[primes[j] * i] = true;
			if (i % primes[j] == 0) break;
		}
	}

	for (int i = 0; i < cnt; i++)
		for (int j = i + 1; j < cnt; j++) dfs(i, primes[i], j, primes[j]);

	sort(all(almost));
	almost.erase(unique(all(almost)), almost.end());
	/*for (auto i : almost) cout << i << endl;
	cout << endl;*/
}

void solve() {
	init();
	
	int n; cin >> n;
	int ans = upper_bound(all(almost), n) - almost.begin();
	cout << ans;
}

int main() {
	solve();
}


59B. Fortune Telling

原题指路:https://codeforces.com/problemset/problem/59/B

题意 ( 2   s ) (2\ \mathrm{s}) (2 s)

给定一个长度为 n    ( 1 ≤ n ≤ 100 ) n\ \ (1\leq n\leq 100) n  (1n100)的序列 a 1 , ⋯   , a n    ( 1 ≤ a i ≤ 100 ) a_1,\cdots,a_n\ \ (1\leq a_i\leq 100) a1,,an  (1ai100),从中选出若干个数使得其中选出的数之和是奇数且最大,输出最大值.若不存在合法的选法,输出 0 0 0.

思路

设所有数的总和为 s u m sum sum,最小的奇数为 s m a l l e s t smallest smallest,奇数的个数为 c n t cnt cnt.

①若无奇数,则不管怎么选总和都是偶数, a n s = 0 ans=0 ans=0.

②若奇数的个数是奇数,则总和是奇数, a n s = s u m ans=sum ans=sum.

③若奇数的个数是偶数,则总和是偶数,总和减去最小的奇数结果是最大的奇数, a n s = s u m − s m a l l e s t ans=sum-smallest ans=sumsmallest.

代码

void solve() {
	int n; cin >> n;

	int sum = 0;  // 总和
	int smallest = INF;  // 最小的奇数
	int cnt = 0;  // 奇数的个数
	while (n--) {
		int x; cin >> x;
		sum += x;
		if (x & 1) {
			smallest = min(smallest, x);
			cnt++;
		}
	}

	if (smallest == INF) cout << 0;  // 无奇数
	else if (cnt & 1) cout << sum;  // 有奇数个奇数,总和也是奇数
	else cout << sum - smallest;  // 总和是偶数,减最小的奇数结果是最大的奇数
}

int main() {
	solve();
}


68A. Irrational problem

原题指路:https://codeforces.com/problemset/problem/68/A

题意 ( 2   s ) (2\ \mathrm{s}) (2 s)

定义函数 f ( x ) = ( ( ( x   m o d   p 1 )   m o d   p 2 )   m o d   p 3 )   m o d   p 4 f(x)=(((x\ \mathrm{mod}\ p_1)\ \mathrm{mod}\ p_2)\ \mathrm{mod}\ p_3)\ \mathrm{mod}\ p_4 f(x)=(((x mod p1) mod p2) mod p3) mod p4.给定 p 1 , p 2 , p 3 , p 4    ( 1 ≤ p i ≤ 1000 ) p_1,p_2,p_3,p_4\ \ (1\leq p_i\leq 1000) p1,p2,p3,p4  (1pi1000),求区间 [ a , b ]    ( 0 ≤ a ≤ b ≤ 31415 ) [a,b]\ \ (0\leq a\leq b\leq 31415) [a,b]  (0ab31415)中有多少个 x   s . t .   f ( x ) = x x\ s.t.\ f(x)=x x s.t. f(x)=x.

思路

注意到 x < y x<y x<y时, x   m o d   y = x x\ \mathrm{mod}\ y=x x mod y=x,为使得 f ( x ) = x f(x)=x f(x)=x,应 p 1 , p 2 , p 3 , p 4 > x p_1,p_2,p_3,p_4>x p1,p2,p3,p4>x.

p = min ⁡ { p 1 , p 2 , p 3 , p 4 } p=\min\{p_1,p_2,p_3,p_4\} p=min{p1,p2,p3,p4},则有解的充要条件是 p > a p>a p>a,且 a n s = [ 0 , p − 1 ] ⋂ [ a , b ] ans=[0,p-1]\bigcap [a,b] ans=[0,p1][a,b]中数的个数.

代码

void solve() {
	int p = INF;
	for (int i = 0; i < 4; i++) {
		int tmp; cin >> tmp;
		p = min(p, tmp);
	}

	int a, b; cin >> a >> b;
	cout << (p > a ? min(p - a, b - a + 1) : 0);
}

int main() {
	solve();
}


84A. Toy Army

原题指路:https://codeforces.com/problemset/problem/84/A

题意 ( 2   s ) (2\ \mathrm{s}) (2 s)

A和B两队人玩射击游戏,游戏有三轮:先A射,再B射,最后A射.轮到每队时,当前活着的队员分别选定对方的队员为攻击目标,全部选定后同时射击,对方的一个队员可同时是我方的多个队员的攻击目标.每个队员被射击后立即死亡.设初始时双方各有 n    ( 2 ≤ n ≤ 1 e 8 , n 是偶数 ) n\ \ (2\leq n\leq 1\mathrm{e}8,n是偶数) n  (2n1e8,n是偶数)个队员,求游戏结束后最多一共射死多少队员.

思路

最优策略:A先射击对方的一半人,对方剩下的一半人射击A的一半人,最后A的一半人射击B剩下的一半人,此时 a n s = 1.5 n ans=1.5n ans=1.5n.

代码

void solve() {
	int n; cin >> n;
	cout << int(n * 1.5);
}

int main() {
	solve();
}


122A. Lucky Division

原题指路:https://codeforces.com/problemset/problem/122/A

题意 ( 2   s ) (2\ \mathrm{s}) (2 s)

只含有数码 4 4 4 7 7 7的数字称为幸运数字,如 4 , 47 , 744 4,47,744 4,47,744.若一个数能被某些幸运数字整除,则称它是几乎幸运的,注意所有幸运数字本身也是几乎幸运的.给定整数 n    ( 1 ≤ n ≤ 1000 ) n\ \ (1\leq n\leq 1000) n  (1n1000),判断它是否是几乎幸运的.

思路

预处理出 [ 1 , 1000 ] [1,1000] [1,1000]内所有幸运数字及其倍数.

代码

const int MAXN = 1005;
bool state[MAXN];  // 记录一个数是否是幸运数字

bool check(int x) {
	string num = to_string(x);
	for (auto ch : num) 
		if (ch != '4' && ch != '7') return false;
	return true;
}

void init() {
	for (int i = 4; i < MAXN; i++) {
		if (state[i]) continue;

		if (check(i)) {
			for (int j = 1;; j++) {
				if (i * j < MAXN) state[i * j] = true;
				else break;
			}
		}
	}
  
  /*for (int i = 4; i < MAXN; i++)
		if (state[i]) cout << i << ' ';
	cout << endl;*/
}

void solve() {
	init();
	int n; cin >> n;
	cout << (state[n] ? "YES" : "NO");
}

int main() {
	solve();
}


172B. Pseudorandom Sequence Period

原题指路:https://codeforces.com/problemset/problem/172/B

题意 ( 2   s ) (2\ \mathrm{s}) (2 s)

随机数生成器按如下递推公式生成: r i = ( a ⋅ r i − 1 + b )   m o d   m r_i=(a\cdot r_{i-1}+b)\ \mathrm{mod}\ m ri=(ari1+b) mod m,其中 a , b , m a,b,m a,b,m为给定的常数, r 0 r_0 r0称为随机数种子.它生成的随机数前面有一段预周期,其后开始进入周期.给定 a , b , m , r 0    ( 1 ≤ m ≤ 1 e 5 , 0 ≤ a , b ≤ 1000 , 0 ≤ r 0 < m ) a,b,m,r_0\ \ (1\leq m\leq 1\mathrm{e}5,0\leq a,b\leq 1000,0\leq r_0<m) a,b,m,r0  (1m1e5,0a,b1000,0r0<m),求最小周期长度.

思路

用一个unordered_map<int,int>记录每个数第一次出现的下标.

m m m最大为 1 e 5 1\mathrm{e}5 1e5,则不超过 1 e 5 1\mathrm{e}5 1e5次会出现循环,直接模拟即可.

代码

const int MAXN = 1e5 + 5;
int a, b, m;
int r[MAXN];
umap<int, int> mp;  // 每个数第一次出现的下标

void solve() {
	cin >> a >> b >> m >> r[0];

	r[1] = (a * r[0] + b) % m;
	mp[r[1]] = 1;

	int ans = 0, i = 2;
	while (true) {
		r[i] = (a * r[i - 1] + b) % m;
		if (mp[r[i]]) {
			ans = r[i];
			break;
		}
		else mp[r[i]] = i;
		i++;
	}

	cout << i - mp[ans];
}

int main() {
	solve();
}


177B2. Rectangular Game

原题指路:https://codeforces.com/problemset/problem/177/B2

题意 ( 2   s ) (2\ \mathrm{s}) (2 s)

n n n个石子平均分为若干行,只保留其中一行,其余行丢弃.重复该过程直至只剩下 1 1 1个石子.该过程可表示为一个序列: c 1 = n , c i > c i + 1    ( 1 ≤ i < k ) , c k = 1 c_1=n,c_i>c_{i+1}\ \ (1\leq i<k),c_k=1 c1=n,ci>ci+1  (1i<k),ck=1.给定一个整数 n    ( 2 ≤ n ≤ 1 e 9 ) n\ \ (2\leq n\leq 1\mathrm{e}9) n  (2n1e9),求最后得到的序列中所有数之和的最大值.

思路

因序列中都是正数,为使得最后得到的序列中所有数之和最大,应使得序列尽可能长,故每次除以该数的最小素因子即可.

直接模拟,注意中途 n n n变为素数时更新答案并退出,否则 n n n为大素数时会TLE.

代码

namespace Pollard_Rho {
	ll smul(ll x, ll y, ll p) {  // 龟速乘:x*y%p
		ll ans = (ll)x * y - (ll)((long double)x * y / p + 0.5L) * p;
		return ans < 0 ? ans + p : ans;
	}

	const int primecnt = 12;
	const int p[primecnt] = { 2,3,5,7,11,13,17,19,23,29,31,37 };  // 前12个素数
	bool miller_rabin(ll x) {
		if (x <= 2) return x == 2;

		ll v1 = x - 1;
		while ((v1 & 1) == 0) v1 >>= 1;  // 处理为奇数

		for (int i = 0; i < primecnt; i++) {
			if (x == p[i]) return true;

			bool flag = 0;
			auto v = v1;
			auto y = qpow(p[i], v, x);
			if (y == 1) flag = 1;
			else {
				while (v < x - 1) {
					if (y == x - 1) {
						flag = 1;
						break;
					}
					v <<= 1;
					y = smul(y, y, x);
				}
			}
			if (!flag) return false;
		}
		return true;
	}

	ll big_rand() {  // 生成随机数
		static auto sd = 19260817;
		sd ^= sd << 13, sd ^= sd >> 17;
		return abs(sd ^= sd << 5);
	}

	ll seed;
	inline auto f(ll a, ll mod) {
		return (smul(a, a, mod) + seed) % mod;
	}

	ll step;
	inline ll floyd(ll n) {  // Floyd判环
		seed = big_rand() % n;
		ll fast, slow, res = 1;
		fast = slow = big_rand() % n;
		fast = f(fast, n);  // 一开始不要先跳两步 

		for (int i = 0; fast != slow; i++) {
			res = smul(res, fast - slow + n, n);  // 段取优化 
			if (!res) res = fast - slow + n;

			if (i % step == 0) {
				ll g = gcd(res, n);
				if (g != 1) return g;

				res = 1;
			}
			fast = f(f(fast, n), n);
			slow = f(slow, n);
		}
		return gcd(res, n);
	}

	ll maxprime;  // 最大素因子
	void pollard_rho(ll n) {
		if (n == 1) return;

		if (miller_rabin(n)) {
			maxprime = max(maxprime, n);
			return;
		}

		ll k = 1;
		step = log(n);
		step = step << 1 | 1;
		while (k == 1) k = floyd(n);
		pollard_rho(k), pollard_rho(n / k);
	}
}
using namespace Pollard_Rho;

void solve() {
	int n; cin >> n;

	int ans = 0;
	while (n != 1) {
		ans += n;

		if (miller_rabin(n)) {
			ans++;
			break;
		}

		for (int i = 2; i <= n / i; i++) {
			if (n % i == 0) {
				n /= i;
				break;
			}
		}
	}
	cout << ans;
}

int main() {
	solve();
}


199A. Hexadecimal’s theorem

原题指路:https://codeforces.com/problemset/problem/199/A

题意 ( 2   s ) (2\ \mathrm{s}) (2 s)

Fibonacci数列: 0 , 1 , 1 , 2 , 3 , 5 , 8 , ⋯ 0,1,1,2,3,5,8,\cdots 0,1,1,2,3,5,8,.输入一个Fibonacci数 n    ( 0 ≤ n < 1 e 9 ) n\ \ (0\leq n<1\mathrm{e}9) n  (0n<1e9),将其表示为三个Fibonacci数之和,输出任一组解.

思路

注意到 0 0 0在本题中也是Fibonacci数.

代码

void solve() {
	int n; cin >> n;
	cout << "0 0 " << n;
}

int main() {
	solve();
}


267A. Subtractions

原题指路:https://codeforces.com/problemset/problem/267/A

题意 ( 2   s ) (2\ \mathrm{s}) (2 s)

给定一对 ( a , b ) (a,b) (a,b),若它们都大于 0 0 0,每次操作将一对数中大的数减去小的数.问一共能进行几次操作.

t    ( 1 ≤ t ≤ 1000 ) t\ \ (1\leq t\leq 1000) t  (1t1000)组测试数据.每组测试数据输入两个整数 a , b    ( 1 ≤ a , b ≤ 1 e 9 ) a,b\ \ (1\leq a,b\leq 1\mathrm{e}9) a,b  (1a,b1e9).

思路

模拟即可.注意操作次数不会大于初始时的 max ⁡ { a , b } \max\{a,b\} max{a,b},故答案不会爆int.

代码

void solve() {
	int a, b; cin >> a >> b;

	int ans = 0;
	while (a && b) {
		if (a == b) {
			ans++;
			break;
		}
			
		if (a > b) swap(a, b);

		ans += b / a;
		b %= a;
	}
	cout << ans << endl;
}

int main() {
	CaseT  // 单测时注释掉该行
	solve();
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值