CodeForces Round #479(Div. 3)
前言
以后不打 Div.3 了,会打 Div.2 和 Div. 1,因为 Div.3 太简单了 (HouZAJ这只渣渣F题WA了6遍还在这里BB)
A. Wrong Subtraction
题意
给定整数n和k,k为操作次数,一次操作为:若n结尾非0则减1,若n结尾为0则把0删除,问最后的n是什么(题目数据保证最后的n是正数)
思路
大体上只是模拟,但是要加快模拟速度,对于结尾非0的,如果k还有剩余就直接求余,不足就慢慢减1,如果结尾是0的就除10,循环到k为0
#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int N = 115;
const int inf = 0x3f3f3f3f;
int main(){
int n, k;
while(~scanf("%d%d", &n, &k)){
while(k){
if(n%10 == 0){
n /= 10;
k--;
}else{
if(k >= n%10){
k -= n%10;
n -= n%10;
}else{
n--;
k--;
}
}
}
printf("%d\n", n);
}
}
B. Two-gram
题意
求作为子串在给定字符串中出现次数最多的字母对(如AA,AB,BA之类的由两个字母组成的字符串)
思路
hash思想,把字母对当作数组下标存起来,每次扫到有这种字母对则对应位置的数组元素值++,最后扫一遍最大的出现的位置,把位置还原为字母对
#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int N = 115;
const int inf = 0x3f3f3f3f;
char s[N];
int cnt[N*N];
int main(){
int n;
while(~scanf("%d%s", &n, s)){
memset(cnt, 0, sizeof(cnt));
for(int i = 0; i < n - 1; i++){
cnt[(s[i] - 'A') * 26 + (s[i + 1] - 'A')]++;
}
int ans = -1;
int pos = 0;
for(int i = 0; i < N*N; i++){
if(ans < cnt[i]){
ans = cnt[i];
pos = i;
}
}
char a = pos/26 + 'A';
char b = pos%26 + 'A';
printf("%c%c\n", a, b);
}
}
C. Less or Equal
题意
给定一个数组,求一个正整数x能满足有k个数小于或等于x,无解输出-1
思路
排序之后,直接看第k位和第k+1位是否相同,相同必定无解,同时如果给定的k=0,而数组中最小的元素又为1,那也是无解的,排除这两种情况后,当k!=0的时候,x可以直接等于第k位的元素,符合要求,当k=0的时候直接输出1
#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int N = 115;
const int inf = 0x3f3f3f3f;
int a[N];
int main(){
int n, k;
while(~scanf("%d%d", &n, &k)){
for(int i = 0; i < n; i++) scanf("%d", &a[i]);
sort(a, a + n);
if(k == 0){
if(a[0] != 1) printf("1\n");
else printf("-1\n");
}else{
if(a[k - 1] == a[k]){
printf("-1\n");
}else{
printf("%d\n", a[k - 1]);
}
}
}
}
D. Divide by three, multiply by two
题意
给定数组,将数组元素重新排序,使得后一个元素是前一个元素/3或*2的结果
思路
因为数组最多100个元素,所以可以直接把答案搜出来,用set来标记元素是否在数组中,直到DFS的搜索深度能够达到数组元素个数,这时把答案保存下来即可。另外,每次搜/3和*2,最后答案还得倒过来,所以可以直接搜索为*3和/2,保存之后的答案无需倒置
#include <iostream>
#include <cstdio>
#include <set>
#include <vector>
using namespace std;
typedef long long ll;
set<ll> st;
vector<ll> vec;
void dfs(ll a, int dpt, int n, ll& ans){
if(dpt == n){
ans = a;
vec.push_back(a);
return;
}
if(ans == -1 && st.find(3*a) != st.end()){
dfs(3*a, dpt + 1, n, ans);
}
if(ans == -1 && a%2 == 0 && st.find(a/2) != st.end() && a%2 == 0){
dfs(a/2, dpt + 1, n, ans);
}
if(ans != -1){
vec.push_back(a);
}
}
int main(){
int n;
while(~scanf("%d", &n)){
vec.clear();
for(int i = 0; i < n; i++){
ll tmp;
scanf("%I64d", &tmp);
st.insert(tmp);
}
ll ans = -1;
for(set<ll>::iterator it = st.begin(); it != st.end() && ans == -1; it++){
dfs(*it, 1, n, ans);
}
for(int i = 0; i < vec.size(); i++){
printf("%I64d", vec[i]);
if(i < vec.size() - 1) putchar(' ');
}
puts("");
}
}
E. Cyclic Components
题意
给定一张图,求图中连通分量是单圈的个数
思路
其实可以想到,单圈中每个点的度数均为2,因此用并查集得出连通分量,然后再去判断连通分量中的每个点是否都是度数为2的点,最后扫一遍得到答案
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 2e5 + 15;
struct edge{
int v, next;
};
bool tag[N];
int ft[N];
int idg[N];
int head[N];
int tot;
edge e[N << 1];
inline void init(int n){
memset(tag, true, sizeof(tag));
memset(head, -1, sizeof(head));
memset(idg, 0, sizeof(idg));
for(int i = 1; i <= n; i++) ft[i] = i;
tot = 0;
}
inline void addEdge(int u, int v){
e[tot].v = v;
e[tot].next = head[u];
head[u] = tot++;
idg[v]++;
}
int mfind(int x){ return x == ft[x] ? x : ft[x] = mfind(ft[x]); }
int main(){
int n, m;
while(~scanf("%d%d", &n, &m)){
init(n);
while(m--){
int u, v;
scanf("%d%d", &u, &v);
addEdge(u, v);
addEdge(v, u);
int p = mfind(u), q = mfind(v);
if(p != q){
ft[q] = p;
}
}
for(int i = 1; i <= n; i++){
if(idg[i] != 2){
tag[mfind(i)] = false;
}
}
int ans = 0;
for(int i = 1; i <= n; i++){
if(mfind(i) == i && tag[i]){
ans++;
}
}
printf("%d\n", ans);
}
return 0;
}
F. Consecutive Subsequence
题意
求最长连续递增子序列,输出下标
思路
实际上可以边读边dp,dp状态方程为 dp[x] = dp[x - 1] + 1,由于x太大,不能用数组保存为下标,所以使用map,dp过程中还有记录x对应在数组中的下标,以及记录前驱的位置,最终找到最大值及其对应下标,并递归输出即可
#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
#include <map>
using namespace std;
const int N = 2e5 + 15;
const int inf = 0x3f3f3f3f;
map<int, int> mp;
map<int, int> mp_pos;
int pre[N];
int res[N];
int tot;
void dfs(int x){
if(x == -1) return;
dfs(pre[x]);
res[tot++] = x;
}
int main(){
int n;
while(~scanf("%d", &n)){
mp.clear();
mp_pos.clear();
tot = 0;
int max_ans = 0, ans_pos;
for(int i = 1; i <= n; i++){
int tmp;
scanf("%d", &tmp);
mp_pos[tmp] = i;
if(mp.find(tmp - 1) == mp.end()){
mp[tmp] = 1;
pre[i] = -1;
}else{
mp[tmp] = mp[tmp - 1] + 1;
pre[i] = mp_pos[tmp - 1];
}
if(max_ans < mp[tmp]){
max_ans = mp[tmp];
ans_pos = i;
}
}
dfs(ans_pos);
printf("%d\n", max_ans);
for(int i = 0; i < tot; i++){
printf("%d", res[i]);
if(i < tot - 1) putchar(' ');
}
puts("");
}
}