Codeforces Round #805 (Div. 3) A - G
作者:互联网
第一次赛中 AK div3,值得纪念!
赛后发现有很多题想的不是很周到,所以晚发了这么久
A - Round Down the Price
找到一个不大于当前数字的 10 的次幂
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
int main()
{
int t;
cin >> t;
while(t--)
{
ll n;
cin >> n;
ll now = 1;
while(now <= n) now *= 10;
cout << n - (now / 10) << endl;
}
return 0;
}
B. Polycarp Writes a String from Memory
强行模拟一下就好了
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
int vis[310];
int main()
{
int t;
cin >> t;
while(t--)
{
string s;
cin >> s;
int ans = 1, cnt = 0;
for(int i='a'; i<='z'; i++) vis[i] = 0;
for(int i=0; i<s.length(); i++)
{
cnt += ++vis[s[i]] == 1;
if(cnt == 4)
{
ans++;
cnt = 1;
for(int i='a'; i<='z'; i++) vis[i] = 0;
vis[s[i]] = 1;
}
}
cout << ans << '\n';
}
return 0;
}
C. Train and Queries
记录一下每个站最早出现的位置和最晚出现的位置,就可以判断一个站台 a 后面是否有存在另一个站台 b
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
int num[maxn];
map<int, int>l, r;
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
int n, m;
scanf("%d%d", &n, &m);
l.clear();
r.clear();
for(int i=1; i<=n; i++) scanf("%d", &num[i]);
for(int i=1; i<=n; i++)
{
r[num[i]] = i;
if(l.count(num[i]) == 0) l[num[i]] = i;
}
while(m--)
{
int x, y;
scanf("%d%d", &x, &y);
if(l[x] && l[x] < r[y]) printf("YES\n");
else printf("NO\n");
}
}
return 0;
}
D. Not a Cheap String
贪心
从价值最大的往价值最低的开始减
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
pii num[maxn];
int vis[maxn];
int main()
{
int t;
cin >> t;
while(t--)
{
string s;
int p, sum = 0;
cin >> s >> p;
for(int i=0; i<s.length(); i++)
{
vis[i] = 0;
num[i] = {s[i] - 'a' + 1, i};
sum += s[i] - 'a' + 1;
}
sort(num, num + s.length());
for(int i=s.length() - 1; sum>p && i>=0; i--)
{
sum -= num[i].first;
vis[num[i].second] = 1;
}
for(int i=0; i<s.length(); i++)
if(vis[i] == 0) cout << s[i];
cout << "\n";
}
return 0;
}
E. Split Into Two Sets
着色 或 并查集
首先能观察出一些普遍的性质:
-
所有数字出现的次数一定是 2 次
-
一个骨牌不能有两个相同的数字
我的代码是着色的方法做的:
假设一个骨牌是在 1 号堆,则与其冲突的(拥有相同数字)骨牌一定是在 2 号堆,模拟一次看看有没有冲突即可
并查集:
显然拥有相同数字的骨牌是可以相互连接的,我们要做的就是将每一堆相互连接的骨牌按数字平均分成两半,因此,如果同一堆里骨牌的数量为奇数,则不能平均分成两半
因此并查集就要做到每一堆里的数量都是偶数的
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
int vis[maxn], num[maxn][2], cnt[maxn];
vector<int>gra[maxn];
bool dfs(int now, int col)
{
if(vis[now]) return vis[now] == col;
vis[now] = col;
bool f = true;
for(int i=0; f && i<gra[num[now][0]].size(); i++)
{
int nex = gra[num[now][0]][i];
if(nex != now)
f = dfs(nex, col ^ 1 ^ 2);
}
for(int i=0; f && i<gra[num[now][1]].size(); i++)
{
int nex = gra[num[now][1]][i];
if(nex != now)
f = dfs(nex, col ^ 1 ^ 2);
}
return f;
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
int n;
scanf("%d", &n);
for(int i=0; i<=n; i++) {vis[i] = cnt[i] = 0; gra[i].clear();}
int f = 1;
for(int i=0; i<n; i++)
{
for(int j=0; j<2; j++)
{
scanf("%d", &num[i][j]);
gra[num[i][j]].push_back(i);
}
if(num[i][0] == num[i][1]) f = 0;
}
for(int i=1; i<=n; i++) if(gra[i].size() != 2) f = 0;
for(int i=0; i<n && f; i++)
{
if(vis[i] == 0) f = dfs(i, 1);
}
if(f) printf("YES\n");
else printf("NO\n");
}
return 0;
}
F. Equate Multisets
有两个操作,直接搜索也显然不现实,考虑能否将两个操作转换成为一个
如果向下整除没有发生取整的情况,那么乘法和除法为可逆,因此考虑将 \(a\) 数组中所有的数字向下除,直到变成奇数,只要 \(b\) 能够转化为这个奇数,则说明他可以变成相对应的 \(a\)
向上乘肯定没办法变成奇数,因此我们考虑将所有的 b 向下除,直到碰到一个 \(a_i\) 转化成的奇数为止
赛中我用了排序,后来发现并不需要,如果 \(b_i\) 和 \(b_j\) 都能到达某奇数,那么肯定可以沿着相同的路线继续往下除,因此就没有说谁一定要先到
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll maxm = 2e6 + 10;
const ll inf = 1e17 + 10;
map<int, int>mp;
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
int n;
scanf("%d", &n);
mp.clear();
for(int i=0; i<n; i++)
{
int x;
scanf("%d", &x);
while((x & 1) == 0)
x >>= 1;
mp[x]++;
}
int ans = 0;
for(int i=0; i<n; i++)
{
int x;
scanf("%d", &x);
while(x)
{
if((x & 1) && mp[x] > 0)
{
mp[x]--;
ans++;
break;
}
x >>= 1;
}
}
if(ans == n) printf("YES\n");
else printf("NO\n");
}
return 0;
}
G. Passable Paths
LCA
在树上找到形容一条链,只用找到链的两个端点即可,因此这题的初始想法就是找端点
第一个端点:深度最深的地方
第二个端点:离第一个端点最远的那个点
找到两个端点之后,就判断一下其他点是否在这个链上:最快的方法就是判断两个端点到这个点 \(p\) 的距离之和,是不是和链长相等
以上倍增 LCA 实现一下就好了,距离的话直接找到根的距离,也就是深度差,容斥一下算距离就好了
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
vector<int>gra[maxn];
int dep[maxn], fa[maxn][25], pa[maxn];
void dfs(int now, int pre, int d)
{
dep[now] = d;
fa[now][0] = pre;
for(auto nex : gra[now])
{
if(nex == pre) continue;
dfs(nex, now, d + 1);
}
}
void init(int n, int rt = 1)
{
dfs(rt, rt, 0);
for(int i=1; i<=20; i++)
for(int j=1; j<=n; j++)
fa[j][i] = fa[fa[j][i-1]][i-1];
}
int LCA(int a, int b)
{
if(dep[a] < dep[b]) swap(a, b);
int dif = dep[a] - dep[b];
for(int i=20; i>=0; i--)
{
if(dif >= (1 << i))
{
dif -= 1 << i;
a = fa[a][i];
}
}
if(a == b) return a;
for(int i=20; i>=0; i--)
{
if(fa[a][i] != fa[b][i])
{
a = fa[a][i];
b = fa[b][i];
}
}
return fa[a][0];
}
int dis(int a, int b)
{
return dep[a] + dep[b] - 2 * dep[LCA(a, b)];
}
int main()
{
int n;
scanf("%d", &n);
for(int i=1; i<n; i++)
{
int x, y;
scanf("%d%d", &x, &y);
gra[x].push_back(y);
gra[y].push_back(x);
}
init(n);
int m;
scanf("%d", &m);
while(m--)
{
int k;
scanf("%d", &k);
int d = -1, a = 0, b = 0, f = 1;
for(int i=0; i<k; i++)
{
scanf("%d", &pa[i]);
if(dep[pa[i]] > d) {a = pa[i]; d = dep[pa[i]];}
}
d = -1;
for(int i=0; i<k; i++)
{
int x = dis(a, pa[i]);
if(d < x)
{
b = pa[i];
d = x;
}
}
for(int i=0; i<k && f; i++)
{
if(dis(a, pa[i]) + dis(b, pa[i]) != d)
f = 0;
}
printf("%s\n", f ? "yes" : "no");
}
return 0;
}
标签:10,const,int,ll,Codeforces,maxn,Div,include,805 来源: https://www.cnblogs.com/dgsvygd/p/16475347.html