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 << '
'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
#define dbg(...)
#endif
void pt() {std::cout << '
'; }
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 << '
';
return;
}
cout << pre[end] - pre[first - 1] << '
';
}
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 << '
'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
#define dbg(...)
#endif
void pt() {std::cout << '
'; }
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 << '
';
} else 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;
}
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 << '
'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
#define dbg(...)
#endif
void pt() {std::cout << '
'; }
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" << '
';
return;
}
}
if(t > 2) {
cout << "NO" << '
';
return;
}
}
for(int i = 0; i < 26; i++) {
if(!chk[i] && !dfs(i)) {
cout << "NO" << '
';
return;
}
}
cout << "YES" << '
';
for(int i = 1; i <= tot; i++) cout << ans[i];
cout << '
';
}
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,nleq 10^{18}),有(m)个物品,每个物品占用容量为(a_i,1leq a_ileq 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 << '
'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
#define dbg(...)
#endif
void pt() {std::cout << '
'; }
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 << '
';
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 << '
';
}
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 << '
'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
#define dbg(...)
#endif
void pt() {std::cout << '
'; }
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" << '
';
else cout << "NO" << '
';
}
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;
}