2019 浙江省大学生程序设计竞赛
E - Sequence in the Pocket
题意:给出一个整数序列,每次可以任意选择一个元素移动到开头,最少需要多少次操作使得序列非递减;
思路:找到从最大值开始依次倒序排序的最长子序列的长度cnt即可,该子序列不需要额外排序,把剩下的每个元素按顺序提到开头即可,答案为n-cnt;
AC code:
void solve() {
int n; cin >> n;
int mx = 0, pos = -1;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
b[i] = a[i];
if (a[i] >= mx) {
mx = a[i];
pos = i;
}
}
sort(b + 1, b + n + 1);
int st = n;
int cnt = 0, now = mx;
for (int i = pos; i >= 1; i --) {
if (a[i] == now) {
cnt ++;
st -= 1;
now = b[st];
}
}
if (cnt == n) {
cout << 0 << endl;
return;
}
cout << n - cnt << endl;
}
F - Abbreviation
题意:给出元音字母,将一个字符串中的元音字母全部删除,注意如果元音字母为首字母则不删除;
思路:按题意模拟删除即可;
AC code:
map<char, int> mp;
void solve() {
string s; cin >> s;
string ans = "";
ans += s[0];
for (int i = 1; i < s.size(); i ++) {
if (!mp[s[i]]) ans += s[i];
}
cout << ans << endl;
}
signed main() {
fast();
int T;
T = 1;
cin >> T;
mp['a'] ++;
mp['e'] ++;
mp['i'] ++;
mp['y'] ++;
mp['o'] ++;
mp['u'] ++;
while (T --) {
solve();
}
return 0;
}
G - Lucky 7 in the Pocket
题意:找出一个最小的幸运数m>=n,m满足能被7整除且不能被4整除;
思路:暴力枚举;
AC code:
void solve() {
int n; cin >> n;
for (int i = n; ; i ++) {
if (i % 7 == 0 && i % 4 != 0) {
cout << i << endl;
return;
}
}
}
H - Singing Everywhere
题意:整数序列中的极大值点为减分点,可以删除序列中的一个整数,减分点最少可以有多少个;
思路:暴力枚举删除每个点的情况,是否会令两边增加/减少减分点即可;
AC code:
void solve() {
int n; cin >> n;
for (int i = 1; i <= n; i ++) cin >> a[i];
int cnt = 0;
unordered_map<int, int> pos;
for (int i = 2; i < n; i ++) {
if (a[i] > a[i - 1] && a[i] > a[i + 1]) {
cnt ++;
pos[i] ++;
}
}
int mx = 0;
for (int i = 1; i <= n; i ++) {
int ca = 0;
bool flag = false;
if (i - 2 >= 1 && a[i - 1] > a[i - 2] && a[i - 1] > a[i + 1]) {
if (!pos[i - 1]) ca --;
} else {
if (pos[i - 1]) ca ++;
}
if (i + 2 <= n && a[i + 1] > a[i + 2] && a[i + 1] > a[i - 1]) {
if (!pos[i + 1]) ca --;
} else {
if (pos[i + 1]) ca ++;
}
mx = max(ca, mx);
}
//cout << cnt << ' ' << mx << "+++" <<endl;
cout << cnt - mx << endl;
}
I - Fibonacci in the Pocket
题意:给出整数l和r,判断l到r的斐波那契数列的奇偶;
思路:数据为天文数字,所以不能直接去判断,通过打表找规律可以看出斐波那契的奇偶每三个为一组变换,由此得出我们只需要去统计两边界l和r的位和,再分别进行模3处理判断奇偶性;
AC code:
void solve() {
string a, b; cin >> a >> b;
int cnta = -1, cntb = 0;
for (auto c : a) cnta += c - '0';
for (auto c : b) cntb += c - '0';
if (cnta % 3 == 1 && cntb % 3 != 1) {
cout << 1 << endl;
} else if (cnta % 3 != 1 && cntb % 3 == 1) {
cout << 1 << endl;
} else {
cout << 0 << endl;
}
}
J - Welcome Party
题意:有n个人参加展会,其中m组人两两互相为朋友,当一个人进入展会时,如果有朋友在展会内,则他会高兴,给出n个人依次进入展会最少能有多少个人不高兴,如果有多种情况,给出最小字典序进入序列;
思路:
首先并查集存取有朋友关系的人的联通块,在该联通块中可以通过人一个人先进入,来换取同一联通块内所有人高兴;
统计联通块的数量即为最少的不高兴的人数;
然后将每个联通块的祖宗节点放入小跟堆优先队列中,队列中的人为当前可以随时进入的人,每次取出最小保证字典序最小;
每次取出时再将当前节点的子节点,即当前人的朋友压入队列中;
最后得到的即为最少不高兴人数的最小入场字典序。
AC code:
int n, m;
int cnt[N], f[N];
vector<int> g[N];
int find(int x) {
if (f[x] != x) f[x] = find(f[x]);
return f[x];
}
void solve() {
cin >> n >> m;
for (int i = 1; i <= n; i ++) {
f[i] = i;
cnt[i] = 0;
g[i].clear();
}
while (m --) {
int u, v; cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
int x = find(v), y = find(u);
if (x == y) continue;
if (x < y) f[y] = x;
else f[x] = y;
}
vector<int> st(n + 1, 0);
vector<int> ans;
int sum = 0;
priority_queue<int, vector<int>, greater<int>> q;
for (int i = 1; i <= n; i ++) {
if (f[i] == i) q.push(i), st[i] = 1;
}
cout << q.size() << endl;
while (!q.empty()) {
auto t = q.top();
q.pop();
ans.push_back(t);
for (auto x : g[t]) {
if (!st[x]) {
st[x] = 1;
q.push(x);
}
}
}
cout << ans[0];
for (int i = 1; i < ans.size(); i ++) cout << ' ' << ans[i];
cout << endl;
}
K - Strings in the Pocket
题意:给出字符串s和字符串t,通过一次操作翻转字符串s的任意连续子区间,可以得到字符串t,这样的操作有多少种;
思路:
字符串s与字符串t不一样:
- 需变区间一定能通过一次翻转来变成字符串t,如果不能,则答案为0;
- 如果能,向该需变区间的两端拓,拓展字符若为回文则可行的操作+1,否则break;
字符串s与字符串t一样:
- 直接统计字符串s中的回文字符串的个数即可;
- 这里用到manacher算法来On统计出字符串s的回文子串数(板子,直接用);
AC code:
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
#define fast() ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
using namespace std;
typedef long long LL;
const int N = 4e6+10, M = 2001;
int len;
string s, t;
int Len[N];
char str[N];
int manacher() {
int mx = 0, id;
int mxx = 0;
for (int i = 1; i < len; i ++) {
if (mx > i) Len[i] = min(mx - i, Len[2 * id - i]);
else Len[i] = 1;
while (str[i + Len[i]] == str[i - Len[i]]) Len[i] ++;
if (Len[i] + i > mx) {
mx = Len[i] + i;
id = i;
mxx = max(mxx, Len[i]);
}
}
int ans = 0;
for (int i = 0; i < len; i ++) {
ans += Len[i] / 2;
}
return ans;
}
void change() {
int k = 0;
str[k ++] = '@';
for (int i = 0; i < len; i ++) {
str[k ++] = '#';
str[k ++] = s[i];
}
str[k ++] = '#';
len = k;
str[k] = 0;
}
void solve() {
cin >> s >> t;
len = s.size();
int L = -1, R = -1;
for (int i = 0; i < len; i ++) {
if (s[i] != t[i]) {
if (L == -1) L = i;
R = i;
}
}
int ans = 0;
if (L != -1) {
int l = L, r = R;
while (l <= R) {
if (s[l] != t[r]) {
cout << 0 << endl;
return;
}
l ++, r --;
}
l = L - 1, r = R + 1;
ans = 1;
while (l >= 0 && r < len) {
if (s[l] == s[r]) ans ++;
else break;
l --, r ++;
}
cout << ans << endl;
} else {
change();
cout << manacher() << endl;
}
}
signed main() {
fast();
int T = 1;
cin >> T;
while (T --) {
solve();
}
return 0;
}