[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 (2≤n≤1000,0≤k≤1000),问 [ 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 (1≤n≤3000),求 [ 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 (1≤n≤100)的序列 a 1 , ⋯ , a n ( 1 ≤ a i ≤ 100 ) a_1,\cdots,a_n\ \ (1\leq a_i\leq 100) a1,⋯,an (1≤ai≤100),从中选出若干个数使得其中选出的数之和是奇数且最大,输出最大值.若不存在合法的选法,输出 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=sum−smallest.
代码
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 (1≤pi≤1000),求区间 [ a , b ] ( 0 ≤ a ≤ b ≤ 31415 ) [a,b]\ \ (0\leq a\leq b\leq 31415) [a,b] (0≤a≤b≤31415)中有多少个 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,p−1]⋂[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 (2≤n≤1e8,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 (1≤n≤1000),判断它是否是几乎幸运的.
思路
预处理出 [ 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=(a⋅ri−1+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 (1≤m≤1e5,0≤a,b≤1000,0≤r0<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 (1≤i<k),ck=1.给定一个整数 n ( 2 ≤ n ≤ 1 e 9 ) n\ \ (2\leq n\leq 1\mathrm{e}9) n (2≤n≤1e9),求最后得到的序列中所有数之和的最大值.
思路
因序列中都是正数,为使得最后得到的序列中所有数之和最大,应使得序列尽可能长,故每次除以该数的最小素因子即可.
直接模拟,注意中途 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 (0≤n<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 (1≤t≤1000)组测试数据.每组测试数据输入两个整数 a , b ( 1 ≤ a , b ≤ 1 e 9 ) a,b\ \ (1\leq a,b\leq 1\mathrm{e}9) a,b (1≤a,b≤1e9).
思路
模拟即可.注意操作次数不会大于初始时的 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();
}