Codeforces Round #470 (Div. 1)
Contests 鏈接:Codeforces Round #470 (Div. 1)
過題數:3
排名:315/1183
A. Primal Sport
題意
AliceAlice 和 BobBob 兩人在玩一個游戲,AliceAlice 先開始,兩人輪流進行,第 ii 次游戲中,對于一個整數 XiXi,選擇一個素數 p<Xip<Xi,然后找到一個最小的整數 YY,使得 Y≥XY≥X 且 YY 能被 pp 整除,將這個數字作為下一次游戲的新值 Xi+1Xi+1 繼續進行游戲,現在游戲已經進行了兩次,得到了 X2X2 的值,問最小的可能的 X0?(X0≥3)X0(X0≥3) 的值為多少。
輸入
輸入為一個整數 X2?(4≤X2≤106)X2(4≤X2≤106),數據保證 X2X2 是合數。
輸出
輸出最小的可能的 X0X0 的值。
樣例
| 14 |
| 輸出 |
| 6 |
| 提示 |
| 設 X0=6X0=6,則其中一種合法的游戲過程如下: 1. AliceAlice 選擇 p=5p=5,X1X1 的值為 1010; 2. BobBob 選擇 p=7p=7,X2X2 的值為 1414。 |
| 20 |
| 輸出 |
| 15 |
| 提示 |
| 設 X0=15X0=15,則其中一種合法的游戲過程如下: 1. AliceAlice 選擇 p=2p=2,X1X1 的值為 1616; 2. BobBob 選擇 p=5p=5,X2X2 的值為 2020。 |
| 8192 |
| 輸出 |
| 8191 |
題解
我們可以根據 XiXi 的值確定 Xi?1Xi?1 的合法的取值區間:[Xi?p+1,Xi][Xi?p+1,Xi],其中 pp 為 XiXi 的最大的質因子,對于 Xi?1≥Xi?p+1Xi?1≥Xi?p+1 的值,只要選擇質數 pp 就可以通過 Xi?1Xi?1 得到 XiXi 的值,對于 Xi?1<Xi?p+1Xi?1<Xi?p+1 的值,如果選擇質數 pp,則只能得到 Xi?pXi?p 的值,如果選擇其他質數,由于 pp 是最大的質因數,選擇其他質數能夠改變的增量一定小于 pp,所以 X′i<XiXi′<Xi。但是最小的 Xi?1Xi?1 并不能得到最小的 Xi?2Xi?2,因此對于 X2X2 我們需要枚舉所有可能的 X1X1 的值,來找到最小的 X0X0 的值。
過題代碼
#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 LOCALfreopen("test.txt", "r", stdin); // freopen("out.txt", "w", stdout);#endif // LOCALios::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
題意
BobBob 從第 11 天到第 nn 天每天堆體積為 ViVi 體積的雪人,第 ii 天的時候每一個已經堆好的雪人會融化 TiTi 的體積,問在第 ii 天當天所有已經堆好的且沒有完全融化的雪人會融化的總的體積。
輸入
第一行包含一個整數 n (1≤n≤105)n (1≤n≤105),第 22 行包含 nn 個整數 V1,V2,?,Vn?(0≤Vi≤109)V1,V2,?,Vn(0≤Vi≤109),第 33 行包含 nn 個整數 T1,T2,?,Tn?(0≤Ti≤109)T1,T2,?,Tn(0≤Ti≤109)。
輸出
輸出 nn 個整數,第 ii 個整數表示第 ii 天融化的雪人體積。
樣例
| 3 10 10 5 5 7 2 |
| 輸出 |
| 5 12 4 |
| 提示 |
| 第一天堆了一個體積為 1010 的雪人,融化了 55 的體積,剩下一個體積為 55 的雪人,第二天堆了一個體積為 1010 的雪人,每個雪人都融化 77 的體積,第一天的 55 體積的雪人全都融化了,第二天的雪人融化了 77 體積,總共融化了 1212 體積,第二天只剩下一個體積為 33 的雪人,第三天堆了一個體積為 55 的雪人,第二天雪人剩下的體積和第三天雪人的體積都大于等于第三天融化的體積,第三天總共融化了 44 體積的雪人。 |
| 5 30 25 20 15 10 9 10 12 4 13 |
| 輸出 |
| 9 20 35 11 25 |
題解
假設第 11 天堆起來的雪人體積為無窮大,那么到第 ii 天的時候這個雪人融化的體積就為 ∑ij=1Tj∑j=1iTj,第 ii 天剛堆起來的雪人沒有受到前 i?1i?1 天融化的影響,但是可以假設這個雪人是從第 11 天堆起來的,第 ii 天的時候融化了 ∑i?1j?1Ti∑j?1i?1Ti 的體積,導致它第 ii 天的體積為 ViVi,因此可以認為這個雪人在第 11 天堆起來的時候的體積為 Vi+∑i?1j=1TjVi+∑j=1i?1Tj,我們將到第 ii 天的所有雪人的體積都轉化為 V′i=Vi+∑i?1j=1TjVi′=Vi+∑j=1i?1Tj 后放入 mapmap 中,到第 ii 天完全融化的雪人就是 V′k≤∑ij=1TjVk′≤∑j=1iTj 的雪人,將這些雪人在第 ii 天融化的體積(V′k?∑i?1j=1TjVk′?∑j=1i?1Tj)計算出來,然后從 mapmap 中刪去它們,再計算第 ii 天能融化體積 TiTi 的雪人的個數 cntcnt(可以 O(1)O(1) 維護),于是第 ii 天融化的雪人體積就為 ∑(V′j?∑i?1k=1Tk)+Ti×cnt∑(Vj′?∑k=1i?1Tk)+Ti×cnt,其中 ∑i?1k=1Tk<V′j≤∑ik=1Tk∑k=1i?1Tk<Vj′≤∑k=1iTk。
過題代碼
#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 LOCALfreopen("test.txt", "r", stdin); // freopen("out.txt", "w", stdout);#endif // LOCALios::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
題意
有兩個長度為 nn 的序列 a1,a2,?,ana1,a2,?,an 和 b1,b2,?,bnb1,b2,?,bn,對于每一個 aiai,在 bb 序列中找到一個數字與其異或,成為新序列的第 ii 個元素 cici,然后從 bb 序列中刪去被選中的數字,求能夠構成的新序列中字典序最小的序列。
輸入
第一行包含一個整數 n (1≤N≤3×105)n (1≤N≤3×105),第二行為 nn 個整數 a1,a2,?,an (0≤ai<230)a1,a2,?,an (0≤ai<230),第三行為 nn 個整數 b1,b2,?,bn (0≤bi<230)b1,b2,?,bn (0≤bi<230)。
輸出
輸出 nn 個整數,第 ii 個整數表示所求新序列的第 ii 項。
樣例
| 3 8 4 13 17 2 7 |
||||||
| 輸出 | ||||||
| 10 3 28 | ||||||
| 提示 | ||||||
8?2=108?2=10,4?7=34?7=3,13?17=2813?17=28。對于其他可能的答案:(25,6,10),(25,3,15),(10,21,10),(15,21,15),(15,6,28)(25,6,10),(25,3,15),(10,21,10),(15,21,15),(15,6,28),都比 (10,3,28)(10,3,28) 的字典序大。
題解將所有 bb 序列中的數字建一棵字典樹,從 11 到 nn 對于每一個 ii,都取一個 bb 序列中與 aiai 異或值最小的,然后將這個數字在字典樹中出現的次數 ?1?1。 過題代碼#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 maxm = 300000 + 100; const int maxn = 300000 * 32 + 100; const int Size = 2; struct Trie {int root, cnt;int val[maxn], tree[maxn][Size];int creat() {++cnt;memset(tree[cnt], 0, sizeof(tree[cnt]));val[cnt] = 0;return cnt;}void Init() {cnt = 0;root = creat();}int id(int x, int dig) {return ((x >> (31 - dig)) & 1);}void add(int x) {int pos = root;for(int i = 0; i < 32; ++i) {int w = id(x, i);if(tree[pos][w] == 0) {tree[pos][w] = creat();}pos = tree[pos][w];++val[pos];}}int query(int x) {int ret = 0;int pos = root;for(int i = 0; i < 32; ++i) {int w = id(x, i);if(tree[pos][w] == 0 || val[tree[pos][w]] == 0) {w = !w;ret |= (1 << (31 - i));}pos = tree[pos][w];--val[pos];}return ret;} }; Trie t; int n, x; int num[maxn];int main() {#ifdef LOCALfreopen("test.txt", "r", stdin); // freopen("out.txt", "w", stdout);#endif // LOCALios::sync_with_stdio(false);while(scanf("%d", &n) != EOF) {t.Init();for(int i = 0; i < n; ++i) {scanf("%d", &num[i]);}for(int i = 0; i < n; ++i) {scanf("%d", &x);t.add(x);}for(int i = 0; i < n; ++i) {if(i != 0) {printf(" ");}printf("%d", t.query(num[i]));}printf("\n");}return 0; }總結以上是生活随笔為你收集整理的Codeforces Round #470 (Div. 1)的全部內容,希望文章能夠幫你解決所遇到的問題。
|