临时组队vp记录2025.5.7
有个队友上形策了,刚好又有个队两个队友上形策了,所以临时组了个三人队vp
比赛链接:https://qoj.ac/contest/1992
A.Scrambled Scrabble
思路:由于这个题算是开局的签到题,这个题交给了临时队友,数据范围不太大,暴力枚举元音数,然后辅音先用NG,然后不够再拆NG即可,可以二分哟。
吐槽:临时队友写错方向+写太久了。其实主要另一个队友后面才辅助他,跟他聊聊思路,这才理清楚。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
string s;
cin >> s;
vector<int>lg(30, 0);
int l0 = 0, l1 = 0;
for (auto i : s)
{
lg[i - 'A' + 1]++;
if (i == 'A' || i == 'E' || i == 'I' || i == 'O' || i == 'U' || i == 'Y')
l0++;
else
l1++;
}
int l = 0, r = l0;
int k = min(lg[7], lg[14]);
l1 -= k * 2;
auto check = [&](int x)->int
{
int num0 = x, num1 = l1, ck = k, la = 0, ans = 0;
if (l0 - lg[25] >= num0)
num1 += lg[25];
else
num1 += l0 - num0;
for (int i = 1; i <= num0; i++)
{
if (ck >= 2)
ans += 5, ck -= 2, la += 2;
else if (ck == 1 && num1)
ans += 4, ck--, la++, num1--;
else if (num1 > 1)
ans += 3, num1 -= 2;
else if (ck && la)
ans += 3, ck--;
else if (num1 && la)
ans += 2, num1--, la--;
else if(ck)
ck--,ans+=3;
else if (la > 1)
ans++, la -= 2;
else
return ans;
}
return ans;
};
int ans=0;
for(int i=1;i<=l0;i++)
ans=max(ans,check(i));
// int ans = 0;
// while (l < r)
// {
// int mid = (l + r + 1) / 2;
// if (check(mid))
// l = mid;
// else
// r = mid - 1;
// }
cout << ans << endl;
}
B.ICPC Square
思路:显然这个数大于D时就是定值了,小于等于D且为S的倍数一定可以一步到达,那么到达的最远端一定是\(min(n,D/S*S*2(向下取S的倍数))\),那么我们可以发现通过这个值除以S,得到S乘以几得到它,如果乘以的是一个偶数,那么一定是最优解(因为\(D/S*S*2\),保证了这个可行性)。如果是奇数,那么就因数分解,然后去看有没有一个和法解,一个因数小于等于D且为S的倍数,且S乘以这个因数-它小于等于D.如果无合法解,那么,这个奇数就减一,然后输出\(max(S,S*r)\)(偶数个时一定是个可行解!),要注意D可以小于S.
吐槽:一开始倒是过的队挺少的,后面我提出思路并写了代码(细节没写好),想让两个队友帮忙理解我的思路,然后帮忙看看代码。然后一个想重敲,换种方式写(Wa),另一个想跟我提他思路,聊了会,他的思路被我否决了,但是没理解我的想法,最后wa了4~5次才过。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
ll l = 1, r = 1e12;
ll n, d, s;
cin >> n >> d >> s;
ll k = d / s * s;
while (l <= r)
{
ll mid = l + r >> 1;
if (1e18 / s <= mid)r = mid - 1;
else
{
if (mid * s > min(2 * k, n))r = mid - 1;
else l = mid + 1;
}
}
ll ans = r * s;
ll ok = 0;
if (r & 1)
{
for (ll j = 1;j * j <= ans;j++)
{
ll l = j, r = ans / j;
if (ans % j == 0)
{
if (l <= d && ans - l <= d && l % s == 0)
{
ok = 1;
}
if (r <= d && ans - r <= d && r % s == 0)ok = 1;
}
}
if (ok == 0)ans -= s;
}
cout << max(ans, s) << endl;
}
C.Saraga
思路:对不起,我没看题,这个临时队友写的。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
string a,b;
cin>>a>>b;
vector<int>la(26,-1);
vector<int>lb(26,-1);
for(int j=0;j<26;j++)
for(int i=1;i<a.length();i++)
if(a[i]=='a'+j){
la[j]=i;
break;
}
for(int j=0;j<26;j++)
for(int i=b.length()-2;i>=0;i--)
if(b[i]=='a'+j){
lb[j]=i;
break;
}
int ans=-1,minn=1e9;
for(int i=0;i<26;i++)
{
if(la[i]!=-1&&lb[i]!=-1&&la[i]+1+(int)b.length()-1-lb[i]<minn)
ans=i,minn=la[i]+1+(int)b.length()-1-lb[i];
}
if(ans==-1)
cout<<-1<<endl;
else
{
for(int i=0;i<=la[ans];i++)
cout<<a[i];
for(int i=lb[ans]+1;i<b.length();i++)
cout<<b[i];
}
}
I.Microwavable Subsequence
思路:得转化成贡献法做题,我们可以发现其等价于每两个最近相同数之间得不同种数的个数的分段贡献。
首先把小于等于M且不在数组的数先抓出来,这个可以直接算贡献,随后,假设所有数的上一位都是n+1,那么从后往前遍历,可以发现如果一个数的上一位置为n+1,那么就把上个位置到这个位置的不同种数字数统计并乘以2加到贡献上(相当于先形成每个pair),否则贡献就直接加不同种数字的个数了,然后每次算完贡献就把之前点位删了,然后这个点位+1,动态维护值即可,单点修改+区间查询,可以树状数组写。
#include<iostream>
#include<vector>
#define ll long long
using namespace std;
const ll N = 3e5 + 5;
struct s
{
ll l, r;
ll sum = 0;
}p[N << 2];
void build(ll i, ll l, ll r)
{
p[i].l = l, p[i].r = r;
if (l == r)return;
build(i << 1, l, l + r >> 1);
build(i << 1 | 1, (l + r) / 2 + 1, r);
}
void update(ll i, ll wz, ll v)
{
if (p[i].l == p[i].r)
{
p[i].sum += v;
return;
}
ll mid = p[i].l + p[i].r >> 1;
if (wz <= mid)update(i << 1, wz, v);
else update(i << 1 | 1, wz, v);
p[i].sum = p[i << 1].sum + p[i << 1 | 1].sum;
}
ll query(ll i, ll l, ll r)
{
ll ans = 0;
if (p[i].l == l && p[i].r == r)return p[i].sum;
ll mid = p[i].l + p[i].r >> 1;
if (l <= mid)ans += query(i << 1, l, min(r, mid));
if (r >= mid + 1)ans += query(i << 1 | 1, max(mid + 1, l), r);
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
ll n, m;
cin >> n >> m;
vector<ll>a(n + 4), vis(m + 4, 0), wz(m + 4, n + 1);
ll ans = 0, cnt = 0;
for (ll i = 1;i <= n;i++)cin >> a[i], vis[a[i]] = 1;
for (ll i = 1;i <= m;i++)cnt += vis[i];
build(1, 1, n);
for (ll i = n;i >= 1;i--)
{
ll d=query(1,i,wz[a[i]]-1);
if(wz[a[i]]==n+1)ans+=d*2;
else ans+=d;
if (wz[a[i]] != n + 1)update(1, wz[a[i]], -1);
wz[a[i]] = i, update(1, i, 1);
}
// cout<<ans<<endl;
ans += (m - cnt) * cnt;
cout << ans << endl;
}
M.Mirror Maze
思路:数据范围小,可暴力,就不说了。
#include <iostream>
#include <algorithm>
#include <vector>
#include <string.h>
using namespace std;
char mp[205][205];
bool vis[205][205][5];
int lg[205][205];
int n, m, b[2][5] = { {0,1,-1,0,0},{0,0,0,1,-1} };
int main()
{
cin >> n >> m;
int all = 0;
for (int i = 1;i <= n;i++)
for (int j = 1;j <= m;j++)
cin >> mp[i][j], all += (mp[i][j] != '.');
vector<string>ans;
auto check = [&](int d, int x, int y)->bool
{
memset(vis, 0, sizeof vis);
memset(lg, 0, sizeof lg);
int sum = 0;
while (sum<all&&x >= 1 && x <= n && y >= 1 && y <= m)
{
if (vis[x][y][d])
break;
vis[x][y][d] = 1;
lg[x][y]++;
if (lg[x][y] == 1 && mp[x][y] != '.')
sum++;
if (mp[x][y] == '.')
x += b[0][d], y += b[1][d];
else
{
if (mp[x][y] == '/')
{
if (d == 1)
d = 4;
else if (d == 2)
d = 3;
else if (d == 3)
d = 2;
else
d = 1;
}
else
{
if (d == 1)
d = 3;
else if (d == 2)
d = 4;
else if (d == 3)
d = 1;
else
d = 2;
}
x += b[0][d], y += b[1][d];
}
}
return sum == all;
};
for (int i = 1;i <= m;i++)
{
if (check(1, 1, i))
ans.push_back("N" + to_string(i));
}
for (int i = 1;i <= m;i++)
{
if (check(2, n, i))
ans.push_back("S" + to_string(i));
}
for (int i = 1;i <= n;i++)
{
if (check(3, i, 1))
ans.push_back("W" + to_string(i));
}
for (int i = 1;i <= n;i++)
{
if (check(4, i, m))
ans.push_back("E" + to_string(i));
}
cout << ans.size() << endl;
for (auto i : ans)
cout << i << " ";
}

浙公网安备 33010602011771号