A. Stair, Peak, or Neither?
问题:
思路:枚举所有合法情况
代码:
#include <iostream>
using namespace std;
void solve() {
int a, b, c;
cin >> a >> b >> c;
if(a < b && b < c) cout << "STAIR" << endl;
else if(a < b && b > c) cout << "PEAK" << endl;
else cout << "NONE" << endl;
}
int main() {
int t;
cin >> t;
while(t -- ) {
solve();
}
return 0;
}
B upscaling
题目:
思路:两个for循环,按照奇数遍历次数和偶数遍历次数分别填充方块
代码:
#include <iostream>
using namespace std;
const int N = 22;
char g[2 * N][2 * N];
void get(int a, int b, char c) {
g[(a - 1) * 2 + 1][(b - 1) * 2 + 1] = c;
g[(a - 1) * 2 + 1][(b - 1) * 2 + 2] = c;
g[(a - 1) * 2 + 2][(b - 1) * 2 + 1] = c;
g[(a - 1) * 2 + 2][(b - 1) * 2 + 2] = c;
}
void solve() {
int n;
cin >> n;
int w = 1;
for(int i = 1; i <= n; i ++ ) {
if(i % 2) {
for(int j = 1; j <= n; j ++ ) {
char c;
if(w ++ % 2) c = '#';
else c = '.';
get(i, j, c);
}
} else {
for(int j = n; j; j -- ) {
char c;
if(w ++ % 2) c = '#';
else c = '.';
get(i, j, c);
}
}
}
for(int i = 1; i <= 2 * n; i ++ ) {
for(int j = 1; j <= 2 * n; j ++ ) {
cout << g[i][j];
}
cout << endl;
}
}
int main() {
int t;
cin >> t;
while(t -- ) {
solve();
}
return 0;
}
C time conversion
问题:
思路:模拟
代码:
#include <iostream>
using namespace std;
void solve() {
string str;
cin >> str;
char a = str[0];
char b = str[1];
string Time;
int t = (b - '0' + (a - '0') * 10);
if(t < 12) Time = " AM";
else Time = " PM";
t %= 12;
if(t == 0) cout << "12";
else if(t < 10) cout << "0" << t;
else cout << t;
for(int i = 2; str[i]; i ++ ) cout << str[i];
cout << Time;
cout << endl;
}
int main() {
int t;
cin >> t;
while(t -- ) {
solve();
}
return 0;
}
D product of binary decimals
问题:
思路:由于1到1e5的十进制二进制数很少,因此考虑爆搜。注意1不能加到我们的bd集合中去,否则dfs会一直递归下去
代码:
#include <iostream>
#include <vector>
using namespace std;
bool flag;
vector<int> bd;
bool get(int x) {
while(x) {
if(x % 10 > 1)
return false;
x /= 10;
}
return true;
}
void dfs(int x) {
if(x == 1) {
flag = true;
return;
}
for(auto t: bd) {
if(!(x % t)) dfs(x / t);
}
}
void solve() {
flag = false;
int n;
cin >> n;
dfs(n);
if(flag) cout << "YES" << endl;
else cout << "NO" << endl;
}
int main() {
for(int i = 2; i <= 1e5; i ++ ) {
if(get(i)) bd.push_back(i);
}
//for(auto t: bd) cout << t << " ";
int t;
cin >> t;
while(t -- ) {
solve();
}
return 0;
}
E nearly shortest repeating substrings
问题:
思路:可以暴力枚举字符串长度的所有约数,对于每个约数判断该约数构成的字符串是否合法。
在判断最多有一个字符不同时由于我们不知道该字符是在开头还是在其他地方,多次判断代码极其复杂,这里可以考虑从前向后搜一遍,从后向前搜一遍
代码:
#include <iostream>
#include <cstring>
using namespace std;
void solve() {
int n;
string str;
cin >> n >> str;
for(int k = 1; k <= n; k ++ ) {
if(n % k) continue;
bool flag = true, flag1 = true;
int cnt = 1;
string str1 = str.substr(0, k);
for(int i = 0, j = 0; i < n; i ++ ) {
if(str[i] != str1[j]) {
if(!cnt) {
flag = false;
break;
}
cnt --;
}
j ++;
if(j == k) j = 0;
}
cnt = 1;
string str2 = str.substr(str.size() - k);
for(int i = str.size() - 1, j = k - 1; i >= 0; i -- ) {
if(str[i] != str2[j]) {
if(!cnt) {
flag1 = false;
break;
}
cnt --;
}
j --;
if(j < 0) j = k - 1;
}
if(flag || flag1) {
cout << k << endl;
return;
}
}
}
int main() {
int t;
cin >> t;
while(t -- ) {
solve();
}
return 0;
}
F 012 tree
问题:
思路: 模拟
代码:
#include <iostream>
using namespace std;
void build() {
}
void solve() {
int a, b, c;
cin >> a >> b >> c;
int twoChil = 1;
int num = 1;
int high = 1;
while(twoChil < a) {
twoChil += num * 2;
num *= 2;
high ++;
}
int last = twoChil - a;
int pre = num - last;
if(c != pre * 2 + last) cout << "-1" << endl;
else {
if(b <= last) {
if(b && pre == 0) cout << high << endl;
else cout << high - 1 << endl;
} else {
b -= last;
int cnt = pre * 2 + last;
if(b % cnt) cout << high + 1 + b / cnt << endl;
else cout << high + b / cnt << endl;
}
}
}
int main() {
int t;
cin >> t;
while(t -- ) {
solve();
}
return 0;
}
G suffering songs
问题:
思路:状态压缩dp。首先观察题目数据,n在18之内,这时可以考虑爆搜+减枝。如果不是题目有明显的可以舍去绝大部分情况的剪枝策略,18这个范围往往会tle,因为歌曲还要求排序。这时候可以考虑状态压缩dp,用二进制数表示出所有状态,2^18并不是一个很大的数,不用担心mle的问题。我们用二进制数,即0, 1串表示出状态后,要考虑如何进行状态转移。我们往序列后添加歌曲的条件是添加的歌曲与序列最后的歌曲音乐类型与作者是否相同,因此可以给dp数组再加上一维,表示目前状态最后一个歌曲的编号,如果i号歌曲在01串对应的需要为0,并且该歌曲与末尾歌曲可以匹配,那么此时i与01串对应位置要置1,并且数组二维下标要变成i
注意,多次比较字符串的操作较慢,最后会t33,这里可以先对字符串进行预处理,或者把字符串映射成数字,第二种操作类似于离散化
代码:
爆搜tle代码,能想到的剪枝策略都用上了,最后t33了:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 20;
int n;
struct Song{
string style;
string author;
int cnt;
bool operator < (const Song &W) const {
return cnt < W.cnt;
}
}song[N];
bool st[N], flag;
bool cmp(int a, int b) {
return a > b;
}
void dfs(int cnt, int u, int num) {
if(cnt == n - num) {
flag = true;
return;
}
if(cnt == 0) {
for(int i = n; i >= 1; i -- ) {
st[i] = true;
dfs(cnt + 1, i, num);
st[i] = false;
}
} else {
for(int i = n; i >= 1; i -- ) {
if(!st[i] && (song[u].author == song[i].author || song[u].style == song[i].style)) {
st[i] = true;
dfs(cnt + 1, i, num);
st[i] = false;
}
}
}
}
void solve() {
flag = false;
cin >> n;
for(int i = 1; i <= n; i ++ ) {
string a, b;
cin >> a >> b;
song[i] = {a, b};
}
for(int i = 1; i <= n; i ++ ) {
for(int j = 1; j <= n; j ++ ) {
if(i == j) continue;
if(song[i].author == song[j].author || song[i].style == song[j].style) song[i].cnt ++;
}
}
sort(song + 1, song + 1 + n);
for(int i = 0; i < n; i ++ ) {
memset(st, 0, sizeof st);
dfs(0, 0, i);
if(flag) {
cout << i << endl;
return;
}
}
}
int main() {
int t;
cin >> t;
while(t -- ) {
solve();
}
return 0;
}
状态压缩ac代码(这里是映射思路):
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 20;
bool dp[1 << N][N];
pair<string, string> s[N];
int fir[N], sec[N];
int n;
int calc(int x) {
int cnt = 0;
while(x) {
if(x & 1) cnt ++;
x >>= 1;
}
return cnt;
}
int find(string a, vector<string> &aa) {
int l = 0, r = aa.size() - 1;
while(l < r) {
int mid = l + r >> 1;
if(aa[mid] >= a) r = mid;
else l = mid + 1;
}
return l;
}
void solve() {
vector<string> aa;
cin >> n;
for(int i = 0; i < 1 << n; i ++ ) {
for(int j = 0; j < n; j ++ ) {
dp[i][j] = false;
}
}
for(int i = 0; i < n; i ++ ) {
string a, b;
cin >> a >> b;
s[i] = {a, b};
aa.push_back(a);
aa.push_back(b);
}
sort(aa.begin(), aa.end());
aa.erase(unique(aa.begin(), aa.end()), aa.end());
for(int i = 0; i < n; i ++ ) {
fir[i] = find(s[i].first, aa);
sec[i] = find(s[i].second, aa);
}
for(int i = 0; i < n; i ++ ) dp[1 << i][i] = true;
for(int i = 0; i < 1 << n; i ++ ) {
for(int j = 0; j < n; j ++ ) {
if(!dp[i][j]) continue;
else {//状态转移
for(int k = 0; k < n; k ++ ) {
if(!(i >> k & 1)) {
if(fir[k] == fir[j] || sec[k] == sec[j]) {
dp[i | (1 << k)][k] = true;
}
}
}
}
}
}
int res = 0;
for(int i = 0; i < 1 << n; i ++ ) {
for(int j = 0; j < n; j ++ ) {
if(dp[i][j]) {
res = max(res, calc(i));
}
}
}
cout << n - res << endl;
}
int main() {
int t;
cin >> t;
while(t -- ) {
solve();
}
return 0;
}
预处理的方法比较简洁:
for(int i = 0; i < n; i ++ ) {
for(int j = 0; j < n; j ++ ) {
if(s[i].first == s[j].first || s[i].second == s[j].second)
g[i][j] = g[j][i] = 1;
}
}