暑期集训赛01
WTing
·
2024-07-02 10:05:25
·
个人记录
第一套
回文立方数 (cube)
当然,让我帮你翻译:
只有 O(N^{\frac{1}{3}}) 个小于或等于 N 的立方数。因此,可以对所有立方数 N 进行暴力搜索,并检查其十进制表示是否是回文。
出题人良心的馈赠。
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n;
namespace GTR {
const int bufl = 1 << 15;
char buf[bufl], *s = buf, *t = buf;
inline int fetch() {
if (s == t) { t = (s = buf) + fread(buf, 1, bufl, stdin); if (s == t) return EOF; }
return *s++;
}
inline int read() {
int a = 0, b = 1, c = fetch();
while (c < 48 || c > 57) b ^= c == '-', c = fetch();
while (c >= 48 && c <= 57) a = (a << 1) + (a << 3) + c - 48, c = fetch();
return b ? a : -a;
}
} using GTR::read;
int judge(int x) {
int p[50] = {0};
int m = 1;
for ( ; x != 0; ++ m, x /= 10) p[m] = x % 10;
-- m;
for (int i = 1, j = m; i <= m / 2; ++ i, -- j) {
if (p[i] != p[j]) {
return 0;
}
}
return 1;
}
signed main() {
n = read();
int ans = 0;
for (int i = 0; i * i * i <= n; ++ i) {
int x = i * i * i;
if (judge(x)) {
ans = x;
}
}
printf("%lld\n", ans);
return 0;
}
数学小店的奇妙兑换 (drink.cpp)
通过观察本题可以得知答案是 \frac{n}{k-1} ,由于数字较大,我们可以使用一个大整数除法的模板来解决本题。
这个问题的本质是学习除法。在原始场景中(10 个饮料瓶,每 3 个瓶子换一瓶饮料,最终能喝 5 瓶饮料),我们可以看到,10 个饮料瓶最终喝了 5 瓶饮料。根据除法的定义:总价除以数量等于单价,得到每瓶饮料的单价是 \frac{10}{5}=2 。得到单价之后,根据除法的定义继续:总价除以单价等于数量,也就是说假设有 n 元,则可以喝 \frac{n}{2} 瓶饮料。
推广到每 k 个瓶子换一瓶饮料,可以简单地发现答案变为 \frac{n}{k-1} 。
如果还需要证明的话,我们可以根据方程的思想来解决这个问题:
两边同时减 1,解得
1 瓶饮料 = $k-1$ 个空瓶子
```cpp
int main() {
#define int long long
int p = 0, q = 0, k = 0, n, j = 0, flag = 0;
scanf("%s %d", a, &q);
q--;
n = strlen(a);
for(int i = 0; i < n; i++){
p = p * 10 + a[i] - '0';
if(p >= q) {
k = p / q;
ans[j++] = k + '0';
p = p % q;
} else ans[j++] = '0';
}
for(int i = 0; i < j; i++) {
if(ans[i] != '0') flag = 1;
if(flag == 1) printf("%c", ans[i]);
}
}
```
## 烧烤(bbq.cpp)
首先暴力肯定是没问题,出题人的良心已经体现在这额外的 $10\%$ 的分数中了。
下面直接介绍正解。
1. **回文判断**:首先通过哈希或者 manacher 快速判断起始字符串是否为回文串。如果是回文串,那么先手玩家立即输掉比赛。
2. **局面分析**:对于任意一个局面,若先手无法进行任何操作,则说明无论删去开头还是结尾都会得到回文串。我们可以发现符合条件的字符串只能形如 `ab`, `abab`, `ababab` 等,这说明终止状态的长度一定是偶数。因此,**输赢只和起始字符串长度的奇偶性有关。**
3. **时间复杂度**:该方法的时间复杂度为 $O(n + q)$,其中 $n$ 是字符串的长度,$q$ 是查询的数量。
```cpp
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int n,q;
string s;
cin>>n>>q>>s;
vector<int> d1(n);
for(int i = 0, l = 0,r = -1; i < n; i++){
int k = (i > r) ? 1 : min(d1[l + r - i],r - i + 1);
while(0 <= i - k && i + k < n && s[i - k] == s[i + k]) k++;
d1[i] = k--;
if(i + k > r){
l = i - k;
r = i + k;
}
}
while(q--){
cin>>l>>r;
l--,r--;
int mid = (l + r)/2;
if((r - l + 1) % 2 == 1 ) {
if(r - l + 1 <= 2 * d1[mid] - 1) cout<<"Cow\n";
else cout<<"Guan\n";
}
else
cout<<"Cow\n";
}
return 0;
}
```
## 神奇树 (growing)
对于这些操作来说,每一个点都有一个加入的时刻,以及每个第二类操作也有一个时刻。
每一个点会被哪些二类操作影响权值呢?也就是那些对其祖先(或自己)的,且操作时间都比这个点加入时间晚的那些操作才会被影响。
所以,我们可以维护每一个点对应的操作序列,以及当前对应的二类操作集合。对于最终形态的树,我们从根节点开始 dfs,遇到一个点之后就将其对应的二类操作全部加入集合内,然后再查询对于这个点的答案,也就是当前集合内时间大于该节点被加入时间对应的二类操作的 x 之和。然后在 dfs 回溯的时候,把这些二类操作全部从集合内删除。
上述这个集合维护的内容其实是:大于某个时间的 x 之和。这个东西可以用线段树或树状数组维护。用树状数组的常数会比线段树小得多。
时间复杂度:$O(Q \log N)$,其中 $N$ 是树的点数。
```
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int, int>;
const int N = 5e5 + 50;
const int mod = 1e9 + 7;
int n, m;
struct fenwick {
ll t[500050];
ll n;
int lowbit(int x) { return x & (-x); }
void update(int x, ll v) {
while (x <= n)
t[x] += v, x += lowbit(x);
}
ll query(ll x) {
ll ret = 0;
while (x)
ret += t[x], x -= lowbit(x);
return ret;
}
ll query(int l, int r) {
if (l > r)
return 0;
return query(r) - query(l - 1);
}
void clear() {
fill(t, t + n + 5, 0);
}
} t;
vector<int> e[N];
int tim[N];
vector<pii> q[N];
ll a[N];
void dfs(int u) {
a[u] = 0;
for (auto [ti, xi] : q[u])
t.update(ti, xi);
a[u] = t.query(tim[u], t.n);
for (auto v : e[u])
dfs(v);
for (auto [ti, xi] : q[u])
t.update(ti, -xi);
}
void solve() {
int Q;
cin >> Q;
t.n = Q + 1;
m = 1;
tim[1] = 1;
for (int i = 1; i <= Q + 5; i++)
q[i].clear(), e[i].clear();
for (int i = 2; i <= Q + 1; i++) {
int ti, vi, xi;
cin >> ti >> vi;
if (ti == 1) {
m++;
e[vi].push_back(m);
tim[m] = i;
} else {
cin >> xi;
q[vi].push_back({i, xi});
}
}
dfs(1);
for (int i = 1; i <= m; i++)
cout << a[i] << " \n"[i == m];
t.clear();
}
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T = 1;
cin >> T;
while (T--) {
solve();
}
return 0;
}
```