Contests 链接:Codeforces Round #470 (Div. 1)
过题数:3
排名:315/1183
A. Primal Sport
题意
Alice A l i c e 和 Bob B o b 两人在玩一个游戏, Alice A l i c e 先开始,两人轮流进行,第 i i 次游戏中,对于一个整数 ,选择一个素数 p<Xi p < X i ,然后找到一个最小的整数 Y Y ,使得 且 Y Y 能被 整除,将这个数字作为下一次游戏的新值 Xi+1 X i + 1 继续进行游戏,现在游戏已经进行了两次,得到了 X2 X 2 的值,问最小的可能的 X0 (X0≥3) X 0 ( X 0 ≥ 3 ) 的值为多少。
输入
输入为一个整数 X2 (4≤X2≤106) X 2 ( 4 ≤ X 2 ≤ 10 6 ) ,数据保证 X2 X 2 是合数。
输出
输出最小的可能的 X0 X 0 的值。
样例
输入 |
---|
14 |
输出 |
6 |
提示 |
设
X0=6
X
0
=
6
,则其中一种合法的游戏过程如下: 1. Alice A l i c e 选择 p=5 p = 5 , X1 X 1 的值为 10 10 ; 2. Bob B o b 选择 p=7 p = 7 , X2 X 2 的值为 14 14 。 |
输入 |
---|
20 |
输出 |
15 |
提示 |
设
X0=15
X
0
=
15
,则其中一种合法的游戏过程如下: 1. Alice A l i c e 选择 p=2 p = 2 , X1 X 1 的值为 16 16 ; 2. Bob B o b 选择 p=5 p = 5 , X2 X 2 的值为 20 20 。 |
输入 |
---|
8192 |
输出 |
8191 |
题解
我们可以根据 Xi X i 的值确定 Xi−1 X i − 1 的合法的取值区间: [Xi−p+1,Xi] [ X i − p + 1 , X i ] ,其中 p p 为 的最大的质因子,对于 Xi−1≥Xi−p+1 X i − 1 ≥ X i − p + 1 的值,只要选择质数 p p 就可以通过 得到 Xi X i 的值,对于 Xi−1<Xi−p+1 X i − 1 < X i − p + 1 的值,如果选择质数 p p ,则只能得到 的值,如果选择其他质数,由于 p p 是最大的质因数,选择其他质数能够改变的增量一定小于 ,所以 X′i<Xi X i ′ < X i 。但是最小的 Xi−1 X i − 1 并不能得到最小的 Xi−2 X i − 2 ,因此对于 X2 X 2 我们需要枚举所有可能的 X1 X 1 的值,来找到最小的 X0 X 0 的值。
过题代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cstring>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <algorithm>
#include <functional>
#include <iomanip>
using namespace std;
#define LL long long
const int maxn = 1000000 + 100;
int cnt, n;
bool vis[maxn];
int prime[maxn];
void Prime() {
for(int i = 2; i < maxn; ++i) {
if(!vis[i]) {
prime[cnt++] = i;
}
for(int j = 0; j < cnt && i < maxn / prime[j]; ++j) {
int k = i * prime[j];
vis[k] = true;
if(i % prime[j] == 0) {
break;
}
}
}
}
int Find(int x) {
int ret;
int xx = x;
for(int i = 0; i < cnt && prime[i] <= xx / prime[i]; ++i) {
while(x % prime[i] == 0) {
x /= prime[i];
ret = prime[i];
}
}
if(x != 1) {
ret = x;
}
return ret;
}
int main() {
#ifdef LOCAL
freopen("test.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif // LOCAL
ios::sync_with_stdio(false);
Prime();
while(scanf("%d", &n) != EOF) {
int Start = Find(n);
int ans = INT_MAX;
for(int i = n - Start + 1; i <= n; ++i) {
int tmp = i - Find(i) + 1;
if(tmp >= 3) {
ans = min(ans, tmp);
}
}
printf("%d\n", ans);
}
return 0;
}
B. Producing Snow
题意
Bob B o b 从第 1 1 天到第 天每天堆体积为 Vi V i 体积的雪人,第 i i 天的时候每一个已经堆好的雪人会融化 的体积,问在第 i i 天当天所有已经堆好的且没有完全融化的雪人会融化的总的体积。
输入
第一行包含一个整数 ,第 2 2 行包含 个整数 V1,V2,⋯,Vn (0≤Vi≤109) V 1 , V 2 , ⋯ , V n ( 0 ≤ V i ≤ 10 9 ) ,第 3 3 行包含 个整数 T1,T2,⋯,Tn (0≤Ti≤109) T 1 , T 2 , ⋯ , T n ( 0 ≤ T i ≤ 10 9 ) 。
输出
输出 n n 个整数,第 个整数表示第 i i 天融化的雪人体积。
样例
输入 |
---|
3 10 10 5 5 7 2 |
输出 |
5 12 4 |
提示 |
第一天堆了一个体积为 的雪人,融化了 5 5 的体积,剩下一个体积为 的雪人,第二天堆了一个体积为 10 10 的雪人,每个雪人都融化 7 7 的体积,第一天的 体积的雪人全都融化了,第二天的雪人融化了 7 7 体积,总共融化了 体积,第二天只剩下一个体积为 3 3 的雪人,第三天堆了一个体积为 的雪人,第二天雪人剩下的体积和第三天雪人的体积都大于等于第三天融化的体积,第三天总共融化了 4 4 体积的雪人。 |
输入 |
---|
5 30 25 20 15 10 9 10 12 4 13 |
输出 |
9 20 35 11 25 |
题解
假设第 天堆起来的雪人体积为无穷大,那么到第 i i 天的时候这个雪人融化的体积就为 ,第 i i 天刚堆起来的雪人没有受到前 天融化的影响,但是可以假设这个雪人是从第 1 1 天堆起来的,第 天的时候融化了 ∑i−1j−1Ti ∑ j − 1 i − 1 T i 的体积,导致它第 i i 天的体积为 ,因此可以认为这个雪人在第 1 1 天堆起来的时候的体积为 ,我们将到第 i i 天的所有雪人的体积都转化为 后放入 map m a p 中,到第 i i 天完全融化的雪人就是 的雪人,将这些雪人在第 i i 天融化的体积()计算出来,然后从 map m a p 中删去它们,再计算第 i i 天能融化体积 的雪人的个数 cnt c n t (可以 O(1) O ( 1 ) 维护),于是第 i i 天融化的雪人体积就为 ,其中 ∑i−1k=1Tk<V′j≤∑ik=1Tk ∑ k = 1 i − 1 T k < V j ′ ≤ ∑ k = 1 i T k 。
过题代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cstring>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <algorithm>
#include <functional>
#include <iomanip>
using namespace std;
#define LL long long
const int maxn = 100000 + 100;
int n, cnt;
LL mp_cnt;
map<LL, int> mp;
map<LL, int>::iterator it, itt;
LL v[maxn], t[maxn];
map<LL, int>::iterator del[maxn];
int main() {
#ifdef LOCAL
freopen("test.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif // LOCAL
ios::sync_with_stdio(false);
while(scanf("%d", &n) != EOF) {
mp_cnt = 0;
for(int i = 1; i <= n; ++i) {
scanf("%I64d", &v[i]);
}
for(int i = 1; i <= n; ++i) {
scanf("%I64d", &t[i]);
t[i] += t[i - 1];
}
mp.clear();
LL ans;
for(int i = 1; i <= n; ++i) {
ans = 0;
cnt = 0;
v[i] += t[i - 1];
++mp[v[i]];
++mp_cnt;
it = mp.upper_bound(t[i]);
for(itt = mp.begin(); itt != it; ++itt) {
ans += ((itt->first) - t[i - 1]) * (itt->second);
del[cnt++] = itt;
mp_cnt -= itt->second;
}
for(int j = 0; j < cnt; ++j) {
mp.erase(del[j]);
}
ans += mp_cnt * (t[i] - t[i - 1]);
if(i != 1) {
printf(" ");
}
printf("%I64d", ans);
}
printf("\n");
}
return 0;
}
C. Perfect Security
题意
有两个长度为 n n 的序列 和 b1,b2,⋯,bn b 1 , b 2 , ⋯ , b n ,对于每一个 ai a i ,在 b b 序列中找到一个数字与其异或,成为新序列的第 个元素 ci c i ,然后从 b b 序列中删去被选中的数字,求能够构成的新序列中字典序最小的序列。
输入
第一行包含一个整数 ,第二行为 n n 个整数 ,第三行为 n n 个整数 。
输出
输出 n n 个整数,第 个整数表示所求新序列的第 i i 项。