namomo camp day1
B - Brexiting and Brentering
字符串替换
void solve()
{
string s; cin>>s;
int n = s.size();
for(int i = n - 1; i >= 0; i--)
{
if(s[i] == 'a' || s[i] == 'e' || s[i] == 'i' ||
s[i] == 'o' || s[i] == 'u')
{
for(int j = 0; j <= i; j++)
cout<<s[j];
cout<<"ntry\n";
return;
}
}
cout<<s<<'\n';
return;
}
A - Amusement Arcade
对于一段区间将其分成两段去做,只考虑其中一段区间即可,不难发现当区间大小为 \(2 ^ a + 1\) 时可以满足条件,判断是否满足 \(n = 2 ^ a + 2 ^ b + 1\) 即可
void solve()
{
ll n;
cin>>n;
ll b1 = 1;
if(n == 1 || n == 3)
{
cout<<1<<'\n';
return;
}
for(int p = 0; p <= 60; p++)
{
if(p) b1 *= 2;
ll b2 = 1;
for(int q = 0; q <= 60; q++)
{
if(q) b2 *= 2;
//cout<<b1 + b2 +<<" "<<b1<<" "<<b2<<'\n';
if(n == b1 + b2 + 1)
{
if(n == 1)
cout<<1<<'\n';
else
cout<<b1 + 1<<'\n';
return;
}
}
}
cout<<"impossible\n";
return;
}
I - Monty's Hall
第一次没选中: \(\dfrac{d - s}{d}\) ,换 \(l\) 个选中了 \(\dfrac{l}{d - s - e}\)
第一次选中: \(\dfrac{s}{d}\) ,换 \(l\) 个还是选中了 \(\dfrac{s - l}{s}\)
答案: $\dfrac{d - s}{d} \times $$\dfrac{l}{d - s - e}$$+\dfrac{s}{d}$$\times \dfrac{s - l}{s}$ ,\(l = \min(s, d - s - e)\)
void solve()
{
int d, s, e; cin>>d>>s>>e;
int l = min(s, d - s - e);
double res = 1.0 * (d - s) / d * l / (d - s - e) + 1.0 * s / d * (s - l) / s;
//cout<<res<<'\n';
printf("%.7lf\n", res);
return;
}
D - Excursion to Porvoo
离线操作,维护区间最小值,再依次加边
用 set 也可以,藕用线段树作,显得我很蠢
const int N = 1e5 + 10;
int n, m, q, cnt[N];
vector<array<int, 2>> event;
vector<array<ll, 2>> e[N];
ll res[N];
struct segtree
{
ll s, w, p;
}seg[N * 4];
void update(int id)
{
seg[id].s = seg[id * 2].s + seg[id * 2 + 1].s;
seg[id].w = min(seg[id * 2].w, seg[id * 2 + 1].w);
if(seg[id * 2].w <= seg[id * 2 + 1].w)
seg[id].p = seg[id * 2].p;
else
seg[id].p = seg[id * 2 + 1].p;
}
void build(int id, int l, int r)
{
if(l == r)
{
seg[id].s = 0, seg[id].w = -1, seg[id].p = l;
return;
}
int mid = (l + r) >> 1;
build(id * 2, l, mid);
build(id * 2 + 1, mid + 1, r);
update(id);
}
void change(int id, int l, int r, int pos, ll s, ll w)
{
if(l == r)
{
seg[id].s = s;
seg[id].w = w;
return;
}
int mid = (l + r) >> 1;
if(pos <= mid)
change(id * 2, l, mid, pos, s, w);
else
change(id * 2 + 1, mid + 1, r, pos, s, w);
update(id);
}
void solve()
{
cin>>n>>m;
int r = n - 1;
for(int i = 1; i <= m; i++)
{
ll u, s, w; cin>>u>>s>>w;
e[u].push_back({w, s});
}
for(int i = 1; i < n; i++)
sort(e[i].begin(), e[i].end());
cin>>q;
for(int i = 1; i <= q; i++)
{
int w; cin>>w;
event.push_back({w, i});
}
sort(event.begin(), event.end());
build(1, 1, r);
//return;
for(auto [w, id] : event)
{
while(seg[1].w < w)
{
ll cost = 1e18;
int pos = seg[1].p;
for(int i = cnt[pos]; i < e[pos].size(); i++)
if(e[pos][i][0] >= w && e[pos][i][1] <= cost)
{
cost = e[pos][i][1];
cnt[pos] = i + 1;
}
// cout<<pos<<" "<<cost<<'\n';
if(cost == 1e18)
{
break;
}
else
{
// cout<<pos<<" "<<cnt[pos]<<" "<<e[pos][cnt[pos] - 1][1]<<" "<<e[pos][cnt[pos] - 1][0]<<'\n';
change(1, 1, r, pos, e[pos][cnt[pos] - 1][1], e[pos][cnt[pos] - 1][0]);
//break;
}
}
// cout<<"calc: "<<w<<" "<<id<<" "<<seg[1].w<<" "<<seg[1].s<<'\n';
if(seg[1].w >= w)
res[id] = seg[1].s;
else
res[id] = -1;
//break;
}
for(int i = 1; i <= q; i++)
{
if(res[i] == -1) cout<<"impossible\n";
else
cout<<res[i]<<'\n';
}
return;
}
H - Looking for Waldo
枚举每个位置和一条边的长度,再二分另一条边的长度,时间复杂度\(O(h^2w\log w)\) 或 \(O(hw^2\log h)\)
好像有更快的立方做法
int n, m;
void solve()
{
cin>>n>>m;
int s[n + 10][m + 10][6];
memset(s, 0, sizeof s);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
{
char x; cin>>x;
if(x == 'W') s[i][j][1] = 1;
else if(x == 'A') s[i][j][2] = 1;
else if(x == 'L') s[i][j][3] = 1;
else if(x == 'D') s[i][j][4] = 1;
else if(x == 'O') s[i][j][5] = 1;
}
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
for(int k = 1; k <= 5; k++)
s[i][j][k] = s[i][j][k] + s[i - 1][j][k] + s[i][j - 1][k] - s[i - 1][j - 1][k];
// for(int k = 1; k <= 5; k++)
// cout<<s[n][m][k]<<'\n';
int res = n * m + 1;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
for(int x2 = i; x2 <= n; x2++)
{
int x = i, y = j;
int l = 1, r = m - j + 1;
bool st = true;
while(l < r)
{
int mid = (l + r) >> 1;
int y2 = y + mid - 1;
bool ok = true;
for(int k = 1; k <= 5; k++)
{
int t = s[x2][y2][k] - s[x2][y - 1][k]
- s[x - 1][y2][k] + s[x - 1][y - 1][k];
//cout<<i<<" "<<j<<" "<<k<<" " <<t<<" "<<mid<<'\n';
if(t == 0)
ok = false;
}
if(ok) r = mid;
else l = mid + 1;
}
for(int k = 1; k <= 5; k++)
{
int y2 = y + l - 1;
int t = s[x2][y2][k] - s[x2][y - 1][k]
- s[x - 1][y2][k] + s[x - 1][y - 1][k];
//cout<<i<<" "<<j<<" "<<k<<" " <<t<<" "<<'\n';
if(t == 0)
st = false;
}
if(st)
res = min((x2 - x + 1) * l, res);
}
//cout<<i<<" "<<j<<" "<<l<<'\n';
if(res == n * m + 1)
cout<<"impossible\n";
else
cout<<res<<'\n';
return;
}
G - Killjoys' Conference
对于每个连通块(哪怕只有一个点),都可以分成两堆,去放进房间,那么设连通块的个数为 \(c\) ,答案即为 \(2 ^ {c - 1} + 1\), 这里 \(c\) 为什么要 -1 手玩一下就懂了
无解情况看样例三分析,存在长度为 \(3\) 的环就无解
typedef long long ll;
//const int mod = 1e9 + 7;
const int N = 1e6 + 10;
ll qmi(ll a, ll b, ll mod)
{
ll ans = 1 % mod;
while(b)
{
if(b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
int n, m, p, f[N];
vector<int> e[N];
bool ok = true;
void dfs(int u, int from)
{
for(auto v : e[u])
{
if(v == from) continue;
if(f[v])
{
if(f[u] - f[v] == 2)
ok = false;
}
else
{
f[v] = f[u] + 1;
dfs(v, u);
}
}
}
void solve()
{
cin>>n>>m>>p;
for(int j = 1; j <= m; j++)
{
int u, v; cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
ll res = 1;
int c = 0;
for(int i = 1; i <= n; i++)
{
if(f[i] == 0)
{
f[i] = 1;
dfs(i, 0);
c++;
}
}
res = res * qmi(2, c - 1, p) % p;
res = res + 1;
res %= p;
if(ok)
cout<<res<<'\n';
else
cout<<"impossible\n";
return;
}
C - Card Trading
藕英语不好,老婆给我读的题,告诉我只要报价为 \(x\) ,\(\min(满足 x \leq 买入价格 的次数,满足 x \geq 卖出价格 的次数) \times x\)
题目要求输出两位小数,那么关于精度问题,可以做一个让价格乘100的操作,最后输出答案的时候再除回去并特判一下,时间复杂度 \(O(N \log N)\)
typedef long long ll;
const int N = 1e6 + 10;
int n;
array<ll, 3> s[N];
ll sa[N], sb[N];
void solve()
{
cin>>n;
for(int i = 1; i <= n; i++)
{
double p; ll a, b;
cin>>p>>a>>b;
ll pp = p * 100ll;
s[i] = {pp, a, b};
}
sort(s + 1, s + 1 + n);
for(int i = 1; i <= n; i++)
sb[i] = sb[i - 1] + s[i][2];
for(int i = n; i >= 1; i--)
sa[i] = sa[i + 1] + s[i][1];
ll r1 = -1, r2 = -1;
for(int i = 1; i <= n; i++)
{
ll t1 = min(sa[i], sb[i]) * s[i][0];
if(t1 > r2)
r1 = s[i][0], r2 = t1;
}
ll t1 = r1 / 100, t3 = r2 / 100;
if(r2 != 0)
{
cout<<t1<<".";
ll t2 = r1 % 100;
if(t2 >= 0 && t2 <= 9)
cout<<0;
cout<<t2<<" ";
cout<<t3<<".";
t2 = r2 % 100;
if(t2 >= 0 && t2 <= 9)
cout<<0;
cout<<t2<<" ";
}
else
printf("impossible\n");
return;
}
F - Hectic Harbour II
模拟起来是两个对顶栈,直接去做复杂度是 \(O(N^2)\) 的,那么我们观察到在拿新的编号 \(i\) 的时候,只要我们的集装箱在 \(i\) 的上面或者下面就对答案有 \(1\) 的贡献,那么我们只需要去维护第 \(x\) 个是从左往右数第 \(y\) 个就可以了,考虑用树状数组去维护区间个数,时间复杂度 \(O(N \log N)\)
对于从左往右的定义:
样例2中
6 4 3
2 4 0 1
6 3 5
看成这样的,就可以去做了
2 4 0 1 5 6 3
const int N = 4e5 + 10;
template<class T>
struct BIT {
T c[N];
int size;
void resize(int s) { size = s;}
T query(int x) { // 1 ... x
assert(x <= size);
T s = 0;
for (; x; x -= x & (-x)) {
s += c[x];
}
return s;
}
void modify(int x, T s) { // a[x] += s
assert(x != 0);
for (; x <= size; x += x & (-x)) {
c[x] += s;
}
}
};
BIT<ll> tr;
int n;
int n1, n2;
int pos[N];
void solve()
{
cin>>n>>n1>>n2;
tr.resize(n + 1);
for(int i = 1; i <= n1; i++)
{
tr.modify(i, 1);
int x; cin>>x;
pos[x] = i;
}
for(int i = n1 + 1, j = 0; i <= n1 + n2; i++, j++)
{
tr.modify(i, 1);
int x; cin>>x;
pos[x] = n1 + n2 - j;
}
int p = n1 + 1, res = 0;
for(int i = 1; i <= n; i++)
{
int rp = tr.query(pos[i]);
int r0 = tr.query(pos[0]);
if(r0 == rp - 1 || r0 == rp + 1)
res++;
tr.modify(pos[i], -1);
}
cout<<res<<'\n';
return;
}
E - Grid Delivery
贪心地去走即可,ak✌直播说的很清楚了
const int N = 2e3 + 10;
int n, m, g[N][N];
void solve()
{
cin>>n>>m;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
{
char x; cin>>x;
if(x == 'C')
g[i][j] = 1;
}
set<int> s;
s.insert(-1);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
{
if(g[i][j] == 0) continue;
auto it = prev(s.upper_bound(j));
if(it == s.begin()) s.insert(j);
else s.erase(it), s.insert(j);
// cout<<i<<" "<<j<<" "<<s.size()<<'\n';
}
cout<<s.size() - 1<<'\n';
return;
}
本文来自博客园,作者:magicat,转载请注明原文链接:https://www.cnblogs.com/magicat/p/17652057.html
浙公网安备 33010602011771号