A - Poisonous Oyster
思路:一个简单的逻辑题吧,第一个人吃了1,2两种牡蛎,第二个人吃了1,3两种牡蛎,既然四个牡蛎里面只有一个有毒,那么可以分四种情况
1.都良好,4牡蛎有毒
2.第一个人良好,第二个人中毒,3牡蛎有毒
3.第一个人中毒,第二个人良好,2牡蛎有毒
4.两个人都中毒,1牡蛎有毒
#include<bits/stdc++.h>
using namespace std;
#define int long long
int t;
int n,k;
int a[200005];
string s1,s2;
void solve()
{
cin>>s1;
cin>>s2;
if(s1=="sick"&&s2=="sick")
{
cout<<1;
}
else if(s1=="fine"&&s2=="fine")
{
cout<<4;
}
else if(s1=="fine"&&s2=="sick")
{
cout<<3;
}
else
{
cout<<2;
}
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
t=1;
while(t--)
solve();
return 0;
}
B - A..B..C
这题的解题关键在于S的长度最大为100,因此我们可以考虑写一个三层循环的代码复杂度最高33*33*34<1e8肯定是可以跑过去的数据的
因此我们可以用a数组去统计'A'出现的位置,b数组去统计'B'出现的位置,c数组去统计'C'出现的位置,然后写一个三重循环,去判断j-i是否等于k-j,同时要满足i<j<k这个条件,然后如果满足就ans++,最后输出ans就可以了
#include<bits/stdc++.h>
using namespace std;
#define int long long
int t;
int n,k;
vector<int> a;
vector<int> b;
vector<int> c;
string s;
void solve()
{
cin>>s;
for(int i=0;i<s.size();i++)
{
if(s[i]=='A')
{
a.push_back(i);
}
else if(s[i]=='B')
{
b.push_back(i);
}
else if(s[i]=='C')
{
c.push_back(i);
}
}
int ans=0;
for(int i:a)
{
for(int j:b)
{
for(int k:c)
{
if(j-i==k-j&&i<j&&j<k)
{
ans++;
}
}
}
}
cout<<ans;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
t=1;
while(t--)
solve();
return 0;
}
C - Make it Simple
思路:就是说给你n个顶点,m条边,让你去掉自环和重复出现的边,一开始没看清题以为是最小生成树,浪费了我五分钟
如果u==v那么就是自环,我们的统计数ans++,但是如何去统计重复边呢?我们可以用map<pair<int,int>,int>来判断某条边是否出现过 ,如果此时mp[{u,v}]==0&&mp[{v,u}]==0,那就说明这条边没有出现过,此时将这两种map都标记为1,然后如果有一个不为0,那么就可以说明是重边,也需要ans++,最后输出ans就可以了
#include<bits/stdc++.h>
using namespace std;
#define int long long
int t;
int n,m;
vector<int> e[200005];
int f[200005];
map<pair<int,int>,int> mp;
void solve()
{
cin >> n >> m;
for(int i = 1; i <= n; i++)
{
f[i] = i;
}
int ans = 0;
for(int i = 1; i <= m; i++)
{
int u, v;
cin >> u >> v;
if(u==v)
{
ans++;
continue;
}
if(mp[{u,v}]==0&&mp[{v,u}]==0)
{
mp[{u,v}]=1;
mp[{v,u}]=1;
}
else
{
ans++;
}
}
cout << ans << "\n";
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
t = 1;
while(t--)
solve();
return 0;
}
D - Swap to Gather
思路:其实这题一上来就会想到往中间靠的思路,我们只需要找到最中间的位置,然后让两边往中间的1靠就可以,然后就是正常写式子就过了,这个也不怎么需要思考
#include<bits/stdc++.h>
using namespace std;
#define int long long
int t;
int n,k;
int a[200005];
string s;
vector<int> p;
void solve()
{
cin>>n;
cin>>s;
s=" "+s;
for(int i=1;i<=n;i++)
{
if(s[i]=='1')
{
p.push_back(i);
}
}
int pos=(p.size()+1)/2-1;
int ans=0;
for(int i=0;i<p.size();i++)
{
if(i<=pos)
ans+=p[pos]-(pos-i)-p[i];
else
{
ans+=abs(p[pos]+(i-pos)-p[i]);
}
}
cout<<ans<<"\n";
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
t=1;
while(t--)
solve();
return 0;
}
E - GCD of Subset
思路:我们其实看到这题就知道时间复杂度最高为O(nlogn)了,我们不妨用一下这种思路,
f[i]数组表示,存进去的都是i的因子
cnt[i]表示,i这个因子出现的数量
ans[i]表示,一定选取a[i]元素的最大gcd的值
我们去预处理每个数的因子,然后碰到a[i]后去统计这些数的因子的数量,最后如果某因子的数量>=k,那么就将其倍数的ans数组赋值为该因子,最后输出ans数组即可
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,k;
int a[2000000];
int cnt[1000005];
int ans[1000005];
vector<int> f[1000005];
signed main()
{
for(int i=1;i<=1e6;i++)
{
for(int j=i;j<1000005;j+=i)
{
f[j].push_back(i);
}
}
cin>>n>>k;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<=n;i++)
{
for(int j:f[a[i]])
{
cnt[j]++;
}
}
for(int i=1;i<1000005;i++)
{
if(cnt[i]>=k)
{
for(int j=i;j<1000005;j+=i)
{
ans[j]=i;
}
}
}
for(int i=1;i<=n;i++)
{
cout<<ans[a[i]]<<"\n";
}
return 0;
}
F - Prefix LIS Query
思路:标准的LIS板题,只需要去维护后缀max即可,上面的线段树是来自群里大神的板子
#include <bits/stdc++.h>
using namespace std;
struct SegmentTree {
int size;
vector<int> tree;
SegmentTree(int n) {
size = 1;
while (size < n) size <<= 1;
tree.assign(2 * size, 0);
}
void update(int idx, int val, int x, int lx, int rx) {
if (rx - lx == 1) {
tree[x] = max(tree[x], val);
return;
}
int mid = (lx + rx) / 2;
if (idx < mid) {
update(idx, val, 2 * x + 1, lx, mid);
} else {
update(idx, val, 2 * x + 2, mid, rx);
}
tree[x] = max(tree[2 * x + 1], tree[2 * x + 2]);
}
void update(int idx, int val) {
update(idx, val, 0, 0, size);
}
int query(int l, int r, int x, int lx, int rx) {
if (l >= rx || r <= lx) return 0;
if (l <= lx && rx <= r) return tree[x];
int mid = (lx + rx) / 2;
return max(query(l, r, 2 * x + 1, lx, mid), query(l, r, 2 * x + 2, mid, rx));
}
int query(int l, int r) {
return query(l, r, 0, 0, size);
}
};
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N, Q;
cin >> N >> Q;
vector<int> A(N);
for (int i = 0; i < N; ++i) {
cin >> A[i];
}
vector<int> sorted_A = A;
sort(sorted_A.begin(), sorted_A.end());
sorted_A.erase(unique(sorted_A.begin(), sorted_A.end()), sorted_A.end());
auto get_rank = [&](int x) {
return lower_bound(sorted_A.begin(), sorted_A.end(), x) - sorted_A.begin();
};
vector<tuple<int, int, int>> queries(Q);
for (int i = 0; i < Q; ++i) {
int R, X;
cin >> R >> X;
queries[i] = {R - 1, X, i};
}
sort(queries.begin(), queries.end());
SegmentTree st(sorted_A.size());
vector<int> ans(Q);
int ptr = 0;
for (int i = 0; i < N; ++i) {
int rank = get_rank(A[i]);
int max_len = st.query(0, rank) + 1;
st.update(rank, max_len);
while (ptr < Q && get<0>(queries[ptr]) == i) {
int X = get<1>(queries[ptr]);
int query_rank = get_rank(X + 1);
ans[get<2>(queries[ptr])] = st.query(0, query_rank);
ptr++;
}
}
for (int i = 0; i < Q; ++i) {
cout << ans[i] << '\n';
}
return 0;
}