Educational Codeforces Round 82 (Rated for Div. 2)
A. Erasing Zeroes
签到。
Code
/*
* Author: heyuhhh
* Created Time: 2020/2/12 22:35:56
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
#define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 100 + 5;
int n;
char s[N];
int pre[N];
void run(){
cin >> (s + 1);
n = strlen(s + 1);
for(int i = 1; i <= n; i++) pre[i] = pre[i - 1] + (s[i] == '0');
int first = -1, end = -1;
for(int i = 1; i <= n; i++) if(s[i] == '1') {
if(first == -1) first = i;
end = i;
}
if(first == -1) {
cout << 0 << '\n';
return;
}
cout << pre[end] - pre[first - 1] << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
int T; cin >> T;
while(T--) run();
return 0;
}
B. National Project
贪心即可。
因为至少要保证一半以上为高质量的公路,所以先计算出至少需要多少天。
然后在此基础上分情况考虑就行。
Code
/*
* Author: heyuhhh
* Created Time: 2020/2/12 22:41:34
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
#define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
int n, g, b;
void run(){
cin >> n >> g >> b;
int need = (n + 1) / 2;
int t = (need + g - 1) / g;
ll tot = 1ll * (t - 1) * (g + b);
ll r = need - 1ll * g * (t - 1);
if(tot + r >= (ll)n) {
cout << tot + r << '\n';
} else cout << n << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
int T; cin >> T;
while(T--) run();
return 0;
}
C. Perfect Keyboard
题意:
给出\(s\)串,\(|s|\leq 200\)。
现在构造一个由\(26\)个小写字母组成的\(t\)串,要求对于任意两个在\(s\)串中相邻的字符,在\(t\)串中都相邻。
如果不能构造则输出NO。
思路:
我们将相邻关系转化为图上面的连边关系,那么如果存在合法的答案,最终的图一定是由若干条链构成(单个点也视为一条链),即不存在一条环。
那么用邻接矩阵表示出图上面的关系然后直接\(dfs\)即可。
实现的时候有点细节,比如要通过删边避免重复走误判环,还要从度数为\(1\)的点开始搜等等。
代码如下:
Code
/*
* Author: heyuhhh
* Created Time: 2020/2/12 22:54:42
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
#define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 200 + 5;
int n, tot;
char s[N], ans[26];
bool mp[26][26], chk[26];
bool dfs(int u) {
chk[u] = true;
ans[++tot] = 'a' + u;
for(int i = 0; i < 26; i++) if(mp[u][i]) {
if(chk[i]) return false;
mp[u][i] = mp[i][u] = 0;
if(!dfs(i)) return false;
mp[u][i] = mp[i][i] = 1;
}
return true;
}
void run(){
memset(chk, 0, sizeof(chk));
memset(mp, 0, sizeof(mp));
tot = 0;
cin >> (s + 1);
n = strlen(s + 1);
for(int i = 2; i <= n; i++) {
mp[s[i] - 'a'][s[i - 1] - 'a'] = mp[s[i - 1] - 'a'][s[i] - 'a'] = 1;
}
for(int i = 0; i < 26; i++) {
int t = 0;
for(int j = 0; j < 26; j++) {
if(mp[i][j]) ++t;
}
if(t == 1) {
if(!chk[i] && !dfs(i)) {
cout << "NO" << '\n';
return;
}
}
if(t > 2) {
cout << "NO" << '\n';
return;
}
}
for(int i = 0; i < 26; i++) {
if(!chk[i] && !dfs(i)) {
cout << "NO" << '\n';
return;
}
}
cout << "YES" << '\n';
for(int i = 1; i <= tot; i++) cout << ans[i];
cout << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
int T; cin >> T;
while(T--) run();
return 0;
}
D. Fill The Bag
题意:
现有一背包,容量为\(n,n\leq 10^{18}\),有\(m\)个物品,每个物品占用容量为\(a_i,1\leq a_i\leq 10^9\),保证对于每个\(a_i\),都存在一个非负整数\(x\),使得\(2^x=a_i\)。
现在可以执行任意次如下操作:将\(a_i\)划分为两个\(\frac{a_i}{2}\)。
现在要用最少的划分次数,来填满这个背包。
思路:
显然可以发现,如果对\(n\)进行二进制分解,那么我们只需要保证对应二进制位上面为\(1\)即可。
所以贪心策略为:对于某一位而言,肯定能用前面的来堆就用前面的,否则就把后面最近的一个分解,使得这一位为\(1\)。
实现时我们从低位到高位考虑,某一位考虑完过后,这一位剩下的显然堆在后面最优。如果从高位往低位考虑,则贪心起来十分困难。
代码如下:
Code
/*
* Author: heyuhhh
* Created Time: 2020/2/12 23:21:06
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
#define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
int a[N];
int cnt[64];
void run(){
for(int i = 0; i < 64; i++) cnt[i] = 0;
ll n; int m;
cin >> n >> m;
ll sum = 0;
for(int i = 1; i <= m; i++) {
cin >> a[i]; sum += a[i];
int x = a[i] / 2, t = 0;
while(x) t++, x /= 2;
++cnt[t];
}
if(sum < n) {
cout << -1 << '\n';
return;
}
int ans = 0;
for(int i = 0; i < 64; i++) {
bool need = false;
if(n >> i & 1) need = true;
if(cnt[i] == 0 && need) {
for(int j = i + 1; j < 64; j++) {
if(cnt[j] >= 1) {
ans += j - i;
for(int k = i; k < j; k++) ++cnt[k];
++cnt[i], --cnt[j];
break;
}
}
}
if(need) --cnt[i];
cnt[i + 1] += cnt[i] / 2;
}
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
int T; cin >> T;
while(T--) run();
return 0;
}
E. Erase Subsequences
题意:
给出一个字符串,现在可以执行如下操作不超过两次:
- 选择任意一个\(s\)串的子序列,然后将其从\(s\)中移除,拼接在\(t\)串后面(初始\(t\)串为空)。
现在给出\(s\)串和\(t\)串,回答是否能从\(s\)串得到\(t\)串。
思路:
可以考虑枚举\(t\)串分隔位置,那么现在就相当于要从\(s\)串中选出两个不相交的子序列分别为\(t_1,t_2\)。
最直接的实现是一个\(O(n^3)\)的\(dp:dp_{i,j,k}\)表示现在位于\(s\)串的第\(i\)位,位于\(t_1\)的第\(j\)位,\(t_2\)的第\(k\)位,转移的时候直接枚举合法状态进行转移。总的时间复杂度为\(O(n^4)\)。
现在我们对这个\(dp\)进行优化。
注意到我们其实并不需要关注\(s\)串匹配在了哪个位置,只要当\(t_1,t_2\)匹配完时,\(s\)串的指针不超过末尾字符即可。
那么定义\(dp_{i,j}:t_1\)匹配到了\(i,t_2\)匹配到了\(j\),此时需要\(s\)的最短长度为多少。那么转移的时候直接\(O(n^2)\)枚举即可。
所以总的时间复杂度为\(O(n^3)\)。
Code
/*
* Author: heyuhhh
* Created Time: 2020/2/13 9:56:57
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
#define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 400 + 5;
int n, m;
char s[N], t[N];
int nxt[N][26];
int dp[N][N];
int solve(char *s, int n, char *t, int m) {
memset(dp, INF, sizeof(dp));
dp[0][0] = 0;
for(int i = 0; i <= n; i++) {
for(int j = 0; j <= m; j++) {
if(i) dp[i][j] = min(dp[i][j], nxt[dp[i - 1][j]][s[i] - 'a']);
if(j) dp[i][j] = min(dp[i][j], nxt[dp[i][j - 1]][t[j] - 'a']);
}
}
return dp[n][m];
}
void run(){
cin >> (s + 1) >> (t + 1);
n = strlen(s + 1);
m = strlen(t + 1);
memset(nxt, 0, sizeof(nxt));
for(int i = 0; i < 26; i++) nxt[n + 1][i] = n + 1;
for(int i = n; i >= 0; i--) {
for(int j = 0; j < 26; j++) {
if(s[i + 1] == 'a' + j) nxt[i][j] = i + 1;
else nxt[i][j] = nxt[i + 1][j];
}
}
int ans = INF;
for(int i = 1; i <= m; i++) {
ans = min(ans, solve(t, i, t + i, m - i));
}
if(ans <= n) cout << "YES" << '\n';
else cout << "NO" << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
int T; cin >> T;
while(T--) run();
return 0;
}
重要的是自信,一旦有了自信,人就会赢得一切。