ATC - abc350
A - Past ABCs
输出题,因为没注意0吃了一发
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
string s;
cin >> s;
int tmp = (s[3] - '0') * 100 + (s[4] - '0') * 10 + s[5] - '0';
if (tmp < 350 && tmp != 316 && tmp > 0) cout << "Yes\n";
else cout << "No\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}
B - Dentist Aoki
好歹毒的一题,判断一下每个洞处理次数是奇数还是偶数
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n, q;
cin >> n >> q;
map<int, int> mp;
for (int i = 0; i < q;i ++ )
{
int x; cin >> x;
mp[x] ++ ;
}
for (auto t : mp)
{
if (t.second % 2 != 0) n -- ;
}
cout << n << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}
C - Sort
从前往后每次贪心去换
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n;
cin >> n;
vector<int> a(n + 1);
vector<int> idx(n + 1);
for (int i = 1; i <= n; i ++ )
{
cin >> a[i];
idx[a[i]] = i;
}
vector<PII> ans;
for (int i = 1; i <= n; i ++ )
{
if (a[i] == i) continue;
ans.push_back({i, idx[i]});
int p1 = a[i], p2 = i;
int q1 = i, q2 = idx[i];
swap(a[q1], a[q2]);
idx[p1] = q2, idx[p2] = q1;
}
cout << ans.size() << '\n';
for (auto t : ans)
{
cout << t.first << ' ' << t.second << '\n';
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}
D - New Friends(完全图边数)
其实就是问完全图的边数,因为最终情况就是完全图
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n, m;
cin >> n >> m;
vector<vector<int>> g(n + 1);
for (int i = 0; i < m; i ++ )
{
int a, b;
cin >> a >> b;
g[a].push_back(b);
g[b].push_back(a);
}
vector<bool> st(n + 1);
int ans = 0, sum = 0, cnt = 0;
function<void(int)> dfs = [&](int u)
{
if (st[u]) return;
st[u] = true;
sum += g[u].size();
cnt ++ ;
for (int i = 0; i < g[u].size(); i ++ )
{
int j = g[u][i];
if (st[j]) continue;
dfs(j);
}
};
for (int i = 1; i <= n; i ++ )
{
sum = 0, cnt = 0;
if (!st[i])
{
dfs(i);
int res = (1 + cnt - 1) * (cnt- 1) / 2;
ans += res - sum / 2;
}
}
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}
E - Toward 0(记忆化搜索)
应该是第一次做到的记忆化搜索?分治的思想,又有点类似dp的状态转移,因为每一步的贪心无法得到全局最优解,所以通过递归解决每次是选择第一种方案还是第二种
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n, a, x, y;
cin >> n >> a >> x >> y;
map<int, double> dp;
function<double(int)> dfs = [&](int u)
{
if (u == 0) return 0.0;
if (dp[u]) return dp[u];
double ans1 = dfs(u / a) + x;
double ans2 = y * 6.0 / 5.0;
for (int i = 2; i <= 6; i ++ ) ans2 += dfs(u / i) / 5.0;
dp[u] = min(ans1, ans2);
return dp[u];
};
printf("%.8lf", dfs(n));
}
signed main()
{
// ios::sync_with_stdio(false);
// cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}
F - Transpose(文艺平衡树)
笑死我了让我碰上一道F,看一眼很明显的文艺平衡树板题,直接抄了个板子来改改过了
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 5e5 + 10;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
int root, idx; // 分别表示根结点编号和当前用到哪个结点
int val[N]; // 结点权值
int pri[N]; // 结点优先级
int sz[N]; // 结点子树大小
int ch[N][2]; // 结点左右儿子
int tag[N]; // 翻转标记
int lz[N]; // 大小写标记
string s;
void pushup(int u) // 更新结点u信息
{
sz[u] = sz[ch[u][0]] + sz[ch[u][1]] + 1;
}
void pushdown(int u)
{
if (lz[u])
{
lz[ch[u][0]] ^= 1;
lz[ch[u][1]] ^= 1;
if (s[val[u]] >= 'a' && s[val[u]] <= 'z') s[val[u]] += 'A' - 'a';
else if (s[val[u]] >= 'A' && s[val[u]] <= 'Z') s[val[u]] += 'a' - 'A';
lz[u] = 0;
}
if (tag[u])
{
swap(ch[u][0], ch[u][1]);
tag[ch[u][0]] ^= 1;
tag[ch[u][1]] ^= 1;
tag[u] = 0;
}
}
void split(int u, int x, int& lt, int& rt) // 把treap分成小于等于x和大于x的两个部分
{
if (u == 0)
{
lt = rt = 0;
return;
}
pushdown(u);
if (sz[ch[u][0]] + 1 <= x) // 当前点小于x,说明分界点在右儿子
{
lt = u;
split(ch[u][1], x - sz[ch[u][0]] - 1, ch[u][1], rt);
}
else // 当前点大于x,说明分界点在左儿子
{
rt = u;
split(ch[u][0], x, lt, ch[u][0]);
}
pushup(u); // 更新结点u信息
}
int merge(int lt, int rt) // 合并根结点编号为lt和rt的两棵treap
{
if (lt == 0 || rt == 0) return lt + rt;
if (pri[lt] > pri[rt]) // lt的优先级比rt大 就把rt合并到lt的右子树
{
pushdown(lt);
ch[lt][1] = merge(ch[lt][1], rt);
pushup(lt);
return lt;
}
else // rt的优先级比lt大 就把lt合并到rt的左子树
{
pushdown(rt);
ch[rt][0] = merge(lt, ch[rt][0]);
pushup(rt);
return rt;
}
}
void getnode(int x) // 创建权值为x的新结点
{
sz[++ idx] = 1;
ch[idx][0] = ch[idx][1] = 0;
val[idx] = x;
tag[idx] = 0;
pri[idx] = rand(); // 优先值取随机数保证树形状随机
}
void insert(int x, char c) // 将权值为x的新结点插入treap
{
int lt, rt;
split(root, x, lt, rt); // 先把原treap分成小于等于x和大于x两个部分
getnode(x); // 创建值为x的结点
root = merge(merge(lt, idx), rt); // 先合并小于等于x的子树和新结点 再将其与大于x的子树合并
return; // 返回新结点编号
}
void dfs(int u)
{
if (!u) return;
pushdown(u);
dfs(ch[u][0]);
if ((s[val[u]] >= 'a' && s[val[u]] <= 'z') || (s[val[u]] >= 'A' && s[val[u]] <= 'Z')) cout << s[val[u]];
dfs(ch[u][1]);
}
void solve()
{
cin >> s;
int n = s.size();
s = " " + s;
for (int i = 1; i <= n; i ++ ) insert(i, s[i]);
stack<int> stk;
for (int i = 1; i <= n; i ++ )
{
if (s[i] == '(') stk.push(i);
else if (s[i] == ')')
{
int l = stk.top();
stk.pop();
int r = i;
int lt, rt, md;
split(root, r, lt, rt);
split(lt, l - 1, lt, md);
tag[md] ^= 1;
lz[md] ^= 1;
root = merge(merge(lt, md), rt);
}
}
dfs(root);
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}
ATC - abc349
E - Weighted Tic-Tac-Toe(博弈+搜索)
如果局部最优解无法推出全局最优解,当前最优的策略可能会让之后处于较劣情况,那就赶紧抛开贪心的想法!
再看一眼范围也不大,于是直接搜索
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
vector<vector<int>> g(4, vector<int>(4)), cl(4, vector<int>(4));
for (int i = 1; i <= 3; i ++ )
for (int j = 1; j <= 3; j ++ )
cin >> g[i][j];
vector<int> score(3);
auto check = [&]()
{
for (int i = 1; i <= 3; i ++ )
{
if (cl[i][1] != 0 && cl[i][1] == cl[i][2] && cl[i][1] == cl[i][3]) return cl[i][1];
if (cl[1][i] != 0 && cl[1][i] == cl[2][i] && cl[1][i] == cl[3][i]) return cl[1][i];
}
if (cl[1][1] != 0 && cl[1][1] == cl[2][2] && cl[1][1] == cl[3][3]) return cl[1][1];
if (cl[1][3] != 0 && cl[1][3] == cl[2][2] && cl[2][2] == cl[3][1]) return cl[1][3];
for (int i = 1; i <= 3; i ++ )
for (int j = 1; j <= 3; j ++ )
if (cl[i][j] == 0) return (int)0;
return score[1] > score[2] ? (int)1 : (int)2;
};
function<int(int)> dfs = [&](int op) // op = 1说明第一个人 op = 0说明第二个人
{
int res = check();
if (res) return res % 2;
for (int i = 1; i <= 3; i ++ )
{
for (int j = 1; j <= 3; j ++ )
{
if (cl[i][j]) continue;
score[op] += g[i][j];
cl[i][j] = op;
int res = dfs(op == 1 ? (int)2 : (int)1);
score[op] -= g[i][j];
cl[i][j] = 0;
if (op % 2 == res) return res;
}
}
return op == 1 ? (int)0 : (int)1;
};
if (dfs(1)) cout << "Takahashi\n";
else cout << "Aoki\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}
F - Subsequence LCM(数位dp)
应该算是数位dp吧,首先想到的肯定是选择的数一定是可以提供m的质因子的,但有个想遗漏的点是,如果m中有5个2,那一定要选择一个可以提供5个2的,多个数拼起来5个2是不可以的
所以先拆出来m中的所有质因子(需要质因子的种类和同种质因子乘起来的值),然后判断a中的每一个数可以给m提供多少价值,最后类似于背包dp
m如果为1的话要特判
实现细节还是蛮多的
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n, m;
cin >> n >> m;
vector<int> prime, val;
int tmp = m;
for (int i = 2; i * i <= m; i ++ )
{
if (tmp % i == 0)
{
prime.push_back(i);
val.push_back(1);
while (tmp % i == 0)
{
val[val.size() - 1] *= i;
tmp /= i;
}
}
}
if (tmp != 1)
{
prime.push_back(tmp);
val.push_back(tmp);
}
vector<int> cnt(1e5 + 10), dp(1e5 + 10);
for (int i = 0; i < n; i ++ )
{
int x; cin >> x;
int res = 0;
for (int j = 0; j < prime.size(); j ++ )
{
if (x % val[j] == 0)
{
x /= val[j];
if (x % prime[j] == 0) break;
res |= (1 << j);
}
while (x % prime[j] == 0) x /= prime[j];
}
if (x == 1) cnt[res] ++ ;
}
vector<int> pw;
pw.push_back(1);
for (int i = 1; i <= n; i ++ ) pw.push_back(pw[pw.size() - 1] * 2 % mod);
dp[0] = pw[cnt[0]];
for (int i = 1; i < (1 << prime.size()); i ++ )
{
for (int j = ((1 << prime.size()) - 1); j >= 0; j -- )
{
dp[i | j] = (dp[i | j] + dp[j] * (pw[cnt[i]] - 1)) % mod;
}
}
if (m == 1) dp[(1 << prime.size()) - 1] -- ;
cout << dp[(1 << prime.size()) - 1] << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}
ATC - abc347
C - Ideal Holidays
每个值模上a+b,就能得出相对位置,然后排序,相邻的两个间距大于等于b,中间就可以塞下一组工作日,就输出Yes
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n, a, b;
cin >> n >> a >> b;
vector<int> d(n);
for (int i = 0; i < n; i ++ )
{
cin >> d[i];
d[i] %= (a + b);
}
sort(d.begin(), d.end());
for (int i = 1; i < d.size(); i ++ )
{
if (d[i] - d[i - 1] - 1 >= b)
{
cout << "Yes\n";
return;
}
}
if (d[0] + a + b - d[d.size() - 1] - 1 >= b) cout << "Yes\n";
else cout << "No\n";
return;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}
D - Popcount and XOR(位运算)
这一题不难但是。。。以后一定不要写(1 << i)
,改成((i64)1 << i)
算我求你了。。。
然后bitset是真的好用啊,查题解的时候看到了别人用
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int a, b, c;
cin >> a >> b >> c;
int cnt = 0;
for (int i = 0; i < 60; i ++ )
if ((1 & (c >> i)) == 1) cnt ++ ;
int sum = a + b;
if (cnt > sum || (sum - cnt) % 2 != 0)
{
cout << "-1\n";
return;
}
int suf = (sum - cnt) / 2;
if (a < suf || b < suf)
{
cout << "-1\n";
return;
}
int x = 0, y = 0;
a -= suf, b -= suf;
for (int i = 0; i < 60; i ++ )
{
if ((1 & (c >> i)) == 1)
{
if (a) x += ((i64)1 << i), a -- ;
else if (b) y += ((i64)1 << i), b -- ;
else
{
cout << "-1\n";
return;
}
}
else if (suf != 0)
{
x += ((i64)1 << i);
y += ((i64)1 << i);
suf -- ;
}
// cout << i << ' ' << x << ' ' << y << '\n';
}
if (suf != 0 || a != 0 || b != 0) cout << -1 << '\n';
else cout << x << ' ' << y << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}
E - Set Add Query(前缀和)
记录下来每次加的值,求个前缀和
然后再根据每个数出现的区间为这一位加上相应的数
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n, m;
cin >> n >> m;
set<int> st;
vector<int> a(m + 1), pre(m + 1);
vector<vector<int>> op(n + 1);
for (int i = 1; i <= m; i ++ )
{
int x; cin >> x;
op[x].push_back(i);
if (st.find(x) == st.end()) st.insert(x);
else st.erase(x);
a[i] = st.size();
}
for (int i = 1; i <= m; i ++ ) pre[i] = pre[i - 1] + a[i];
pre.push_back(pre[pre.size() - 1]);
for (int i = 1; i <= n; i ++ )
{
op[i].push_back(m + 1);
int res = 0;
for (int j = 1; j < op[i].size(); j += 2)
{
int p = op[i][j], q = op[i][j - 1];
res += pre[p - 1] - pre[q - 1];
}
cout << res << ' ';
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}
F - Non-overlapping Squares(分类讨论+二维前缀和)
在正方形里面取三个小正方形只有这六种情况
dp[i][j][0/1/2/3]
分别表示以当前点为小正方形的右下角、左下角、右上角、左上角的和,六种情况分别算一下
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n, m;
int ans = 0;
cin >> n >> m;
vector<vector<int>> a(n + 2, vector<int>(n + 2)), pre(n + 2, vector<int>(n + 2));
vector<vector<vector<int>>> dp(n + 2, vector<vector<int>>(n + 2, vector<int>(4)));
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
cin >> a[i][j];
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
pre[i][j] = pre[i - 1][j] + pre[i][j - 1] - pre[i - 1][j - 1] + a[i][j];
for (int i = n; i >= m; i -- )
for (int j = n; j >= m; j -- )
pre[i][j] = pre[i][j] - pre[i - m][j] - pre[i][j - m] + pre[i - m][j - m];
for (int i = m; i <= n; i ++ )
for (int j = m; j <= n; j ++ )
dp[i][j][0] = max({pre[i][j], dp[i - 1][j][0], dp[i][j - 1][0]});
for (int i = m; i <= n; i ++ )
for (int j = n - m + 1; j > 0; j -- )
dp[i][j][1] = max({pre[i][j + m - 1], dp[i - 1][j][1], dp[i][j + 1][1]});
for (int i = n - m + 1; i > 0; i -- )
for (int j = m; j <= n; j ++ )
dp[i][j][2] = max({pre[i + m - 1][j], dp[i][j - 1][2], dp[i + 1][j][2]});
for (int i = n - m + 1; i > 0; i -- )
for (int j = n - m + 1; j > 0; j -- )
dp[i][j][3] = max({pre[i + m - 1][j + m - 1], dp[i + 1][j][3], dp[i][j + 1][3]});
for (int i = m; i <= n; i ++ )
for (int j = m; j <= n; j ++ )
{
ans = max(ans, dp[n][j - m][0] + pre[i][j] + dp[1][j + 1][3]);
ans = max(ans, dp[i - m][n][0] + pre[i][j] + dp[i + 1][1][3]);
ans = max(ans, dp[n][j][0] + dp[i][j + 1][1] + dp[i + 1][j + 1][3]);
ans = max(ans, dp[i][j][0] + dp[i + 1][j][2] + dp[1][j + 1][3]);
ans = max(ans, dp[i][n][0] + dp[i + 1][j][2] + dp[i + 1][j + 1][3]);
ans = max(ans, dp[i][j][0] + dp[i][j + 1][1] + dp[i + 1][1][3]);
}
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}
CF 1704D Magical Array(非常妙的前缀和)
发现操作1对 ∑ i = 1 n a i × i \sum_{i=1}^{n}{a_i\times i} ∑i=1nai×i 没有影响,操作2对它的影响是每次加1,所以只要求前面这个式子,找到值不一样的那个,再求差就可以了
学到了max_element
函数,好用
想不到啊。。。
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n, m;
cin >> n >> m;
vector<int> sum(n);
for (int i = 0; i < n; i ++ )
{
int res = 0;
for (int j = 1; j <= m; j ++ )
{
int x; cin >> x;
res += x * j;
}
sum[i] = res;
}
int idx = max_element(sum.begin(), sum.end()) - sum.begin();
cout << idx + 1 << ' ' << sum[idx] - sum[min_element(sum.begin(), sum.end()) - sum.begin()] << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
}
ATC - abc346
C - Σ
暴力
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n, k;
cin >> n >> k;
set<int> st;
for (int i = 0; i < n; i ++ )
{
int x; cin >> x;
st.insert(x);
}
int idx = 1, ans = 0;
for (auto t : st)
{
while (t != idx)
{
ans += idx, idx ++ ;
if (idx > k) break;
}
idx ++ ;
if (idx > k) break;
}
if (idx < k) ans += (idx + k) * (k - idx + 1) / 2;
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}
D - Gomamayo Sequence(前缀和)
这两天怎么一直在做前缀和啊好奇怪
因为最后的情况其实很固定,如果确定了哪两个相邻的数是一样的,整个字符串就已经固定了,所以先求出把原字符串变成“10101010…”的代价前缀和,再求出把原字符串变成“01010101^”的代价前缀和,然后枚举让哪两个位置一样,前一半用一个前缀和算代价,后一半用另一个前缀和算就可以
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n;
string s;
cin >> n >> s;
vector<int> c(n);
for (int i = 0; i < n; i ++ ) cin >> c[i];
string s1 = "", s2 = "";
for (int i = 0; i < n; i ++ )
{
if (i & 1)
{
s1.push_back('0');
s2.push_back('1');
}
else
{
s1.push_back('1');
s2.push_back('0');
}
}
vector<int> res1(n), res2(n);
if (s[0] == '1') res2[0] = c[0];
else res1[0] = c[0];
for (int i = 1; i < n; i ++ )
{
res1[i] = res1[i - 1], res2[i] = res2[i - 1];
if (s1[i] != s[i]) res1[i] += c[i];
if (s2[i] != s[i]) res2[i] += c[i];
}
int ans = INF;
for (int i = 1; i < n; i ++ )
{
// 换成1
if (i & 1) ans = min(ans, res1[i - 1] + res2[n - 1] - res2[i - 1]);
else ans = min(ans, res2[i - 1] + res1[n - 1] - res1[i - 1]);
// 换成0
if (i & 1) ans = min(ans, res2[i - 1] + res1[n - 1] - res1[i - 1]);
else ans = min(ans, res1[i - 1] + res2[n - 1] - res2[i - 1]);
}
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}
E - Paint(逆向思考)
因为之后涂的颜色会对前面有影响,所以直接逆向思考,从后往前看,如果这个位置在后面涂过颜色了就直接忽略前面涂的颜色
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n, m, q;
cin >> n >> m >> q;
vector<bool> r(n + 1), c(m + 1);
map<int, int> mp;
int cnt1 = 0, cnt2 = 0;
vector<array<int, 3>> a(q);
for (int i = 0; i < q; i ++ ) cin >> a[i][0] >> a[i][1] >> a[i][2];
for (int i = q - 1; i >= 0; i -- )
{
int op = a[i][0], x = a[i][1], cl = a[i][2];
if (op == 1)
{
if (r[x]) continue;
mp[cl] += m - cnt2;
r[x] = true;
cnt1 ++ ;
}
else
{
if (c[x]) continue;
mp[cl] += n - cnt1;
c[x] = true;
cnt2 ++ ;
}
}
int sum = 0;
for (auto t : mp)
{
if (t.first == 0) continue;
sum += t.second;
}
sum = n * m - sum;
mp[0] = sum;
vector<PII> ans;
for (auto t : mp)
{
if (t.second > 0)
{
ans.push_back(t);
}
}
cout << ans.size() << '\n';
for (auto t : ans) cout << t.first << ' ' << t.second << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}
F - SSttrriinngg in StringString
本来的想法是先把确定的那个串拼好,但是发现实在是太长了根本不可能拼好,所以还是循环来看
很明显的二分,难点就是怎么去写这个check函数,从前往后看t串,t的每一位必须出现mid次才轮到下一位出现,小暴力循环s,实现起来还是很多细节的
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int maxn = 1e6 + 10;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n;
string s, t;
cin >> n >> s >> t;
vector<vector<int>> pos(26);
for (int i = 0; i < s.size(); i ++ ) pos[s[i] - 'a'].push_back(i);
auto check = [&](int x)
{
if (x == 0) return true;
int it = 0, sum = 0, cur = 0, left = x;
while (sum <= n && cur < t.size())
{
int c = t[cur] - 'a';
if (pos[c].size() == 0) return false;
if (it == 0)
{
int cnt = pos[c].size();
int cost = left / cnt;
sum += cost;
left -= cost * cnt;
int md = left % cnt;
if (md != 0)
{
sum ++ ;
it = (pos[c][md - 1] + 1) % s.size();
left -= md;
}
else
{
it = (pos[c].back() + 1) % s.size();
}
}
else
{
int st = lower_bound(pos[c].begin(), pos[c].end(), it) - pos[c].begin();
int cnt = pos[c].size() - st;
if (left > cnt)
{
left -= cnt;
it = 0;
}
else
{
it = (pos[c][st + left - 1] + 1) % s.size();
left = 0;
}
}
if (left == 0)
{
cur ++ ;
left = x;
}
}
return sum <= n;
};
int l = 0, r = 1e17;
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
cout << r << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}
ATC - abc345
C - One Time Swap
简单的组合数学
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int maxn = 1e6 + 10;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
string s;
cin >> s;
map<int, int> mp;
for (auto t : s) mp[t - 'a'] ++ ;
int sum = 0, ans = 0;
for (auto t : mp) sum += t.second;
bool flag = false;
for (auto t : mp)
{
if (t.second > 1) flag = true;
ans += t.second * (sum - t.second);
}
ans /= 2;
if (flag) ans ++ ;
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}
D - Tiling
数据范围很小,爆搜一下,但是码力有点烂的我受不了了
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int maxn = 1e6 + 10;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n, h, w;
cin >> n >> h >> w;
vector<PII> a(n + 1);
for (int i = 1; i <= n; i ++ ) cin >> a[i].first >> a[i].second;
vector<vector<int>> st(h + 1, vector<int>(w + 1));
vector<bool> used(n + 1);
auto check = [&](int id)
{
for (int i = 1; i <= h; i ++ )
{
for (int j = 1; j <= w; j ++ )
{
if (st[i][j]) continue;
if (i + a[id].first - 1 <= h && j + a[id].second - 1 <= w)
{
bool flag = true;
for (int ii = i; ii < i + a[id].first; ii ++ )
{
for (int jj = j; jj < j + a[id].second; jj ++ )
{
if (st[ii][jj] > 0)
{
flag = false;
break;
}
}
if (!flag) break;
}
if (flag)
{
for (int ii = i; ii < i + a[id].first; ii ++ )
for (int jj = j; jj < j + a[id].second; jj ++ )
st[ii][jj] = id;
return true;
}
}
}
}
return false;
};
auto del = [&](int id)
{
for (int i = 1; i <= h; i ++ )
for (int j = 1; j <= w; j ++ )
if (st[i][j] == id) st[i][j] = 0;
};
function<bool(int)> dfs = [&](int sum)
{
if (sum == h * w) return true;
for (int i = 1; i <= n; i ++ )
{
if (used[i]) continue;
if (check(i))
{
used[i] = true;
if (dfs(sum + a[i].first * a[i].second)) return true;
used[i] = false;
del(i);
}
swap(a[i].first, a[i].second);
if (check(i))
{
used[i] = true;
if (dfs(sum + a[i].first * a[i].second)) return true;
used[i] = false;
del(i);
}
swap(a[i].first, a[i].second);
}
return false;
};
if (dfs(0)) cout << "Yes\n";
else cout << "No\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}
CF 1572A Book(拓扑排序)
应该是一道很简单的拓扑排序,想的时候没有搞清楚前后结点的转换关系
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int maxn = 1e6 + 10;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n;
cin >> n;
vector<vector<int>> g(n + 1);
vector<int> ind(n + 1), tm(n + 1);
queue<int> q;
int cnt = 0;
for (int i = 1; i <= n; i ++ )
{
int k; cin >> k;
for (int j = 0; j < k; j ++ )
{
int x; cin >> x;
g[x].push_back(i);
}
ind[i] += k;
if (k == 0)
{
q.push(i);
tm[i] = 1;
cnt ++ ;
}
}
while (q.size())
{
auto t = q.front();
q.pop();
for (int i = 0; i < g[t].size(); i ++ )
{
int j = g[t][i];
if (j > t) tm[j] = max(tm[j], tm[t]);
else tm[j] = max(tm[j], tm[t] + 1);
ind[j] -- ;
if (ind[j] == 0)
{
q.push(j);
cnt ++ ;
}
}
}
if (cnt != n)
{
cout << "-1\n";
return;
}
int ans = 0;
for (int i = 1; i <= n; i ++ ) ans = max(ans, tm[i]);
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
}
CF 1036C Classy Numbers(枚举+二分)
首先枚举出所有符合条件的数,然后二分查找
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int maxn = 1e6 + 10;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
vector<int> v;
void dfs(int cur, int cnt, int len)
{
v.push_back(cur);
if (len == 18) return;
dfs(cur * 10, cnt, len + 1);
if (cnt < 3)
{
for (int i = 1; i <= 9; i ++ )
{
dfs(cur * 10 + i, cnt + 1, len + 1);
}
}
}
void pre()
{
for (int i = 1; i <= 9; i ++ ) dfs(i, 1, 1);
v.push_back(1e18);
sort(v.begin(), v.end());
}
void solve()
{
int l, r;
cin >> l >> r;
int ll = lower_bound(v.begin(), v.end(), l) - v.begin();
int rr = upper_bound(v.begin(), v.end(), r) - v.begin();
cout << rr - ll << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
pre();
int t = 1;
cin >> t;
while (t--)
{
solve();
}
}
CF 1554C Mikasa(位运算)
一开始想着二分但是这个范围也太大了,二分肯定会爆
查了题解,首先把 n ^ m = x
换成 n ^ x = m
(交换律)
所以我们要找的就是满足 n ^ x >= (m + 1)
最小的 x
从高位到低位一位一位看,如果当前位:
n
为0
,m+1
为0
,那么x
为0
n
为0
,m+1
为1
,那么x
为1
n
为1
,m+1
为0
,那么x
为0
,且直接跳出n
为1
,m+1
为1
,那么x
为0
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int maxn = 1e6 + 10;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n, m;
cin >> n >> m;
int ans = 0;
for (int i = 32; i >= 0; i -- )
{
if (!((n >> i) & 1) && !(((m + 1) >> i) & 1)) continue;
else if (((n >> i) & 1) && !(((m + 1) >> i) & 1)) break;
else if (!((n >> i) & 1) && (((m + 1) >> i) & 1)) ans += (1 << i);
}
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
}
CF 1327E Count The Blocks(计数)
计数题又没有做出来 唉
首先要去想怎么构造字符串能对长度为 i 的答案有1的贡献,很容易想到这个长度为 i 的部分有三种可能:
- 在整个长度为 n 的字符串的最左边
- 在整个长度为 n 的字符串的最右边
- 在整个长度为 n 的字符串的中间
第一种和第二种情况,只要确保和长度为 i 的部分相邻的那一个元素与长度为 i 的部分取值不同即可
第三种情况,需要确保和长度为 i 的部分相邻的两个元素与长度为 i 的部分取值不同
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int maxn = 1e6 + 10;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
int qpow(int a, int n, int p)
{
int res = 1;
while (n)
{
if (n & 1) res = res * a % p;
a = a * a % p;
n >>= 1;
}
return res;
}
void solve()
{
int n;
cin >> n;
vector<int> dp(n + 1);
dp[n] = 10, dp[n - 1] = 180;
for (int i = n - 2; i >= 1; i -- )
{
dp[i] = (10 * 9 * qpow(10, n - i - 1, mod) % mod * 2 % mod + 10 * 9 * 9 * qpow(10, n - i - 2, mod) % mod * (n - i - 1) % mod) % mod;
}
for (int i = 1; i <= n; i ++ ) cout << dp[i] << ' ';
cout << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}
CF 1381B Unmerge(背包dp)
跑了一发剪枝的dfs爆了,果然cf没有暴力题
然后很容易发现,一个数与这个数之后出现的第一个比它大的数,中间的所有数都应该和这个数在同一个数组,并且排在这个数后面
根据这个,可以将原数组分成很多个小段,然后类似背包去做就可以了
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 1e5 + 10;
const int maxn = 1e6 + 10;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n;
cin >> n;
vector<int> a;
int maxx = 0;
for (int i = 1; i <= 2 * n; i ++ ) {
int x; cin >> x;
if (x < maxx) a[a.size() - 1] ++ ;
else {
a.push_back(1);
maxx = x;
}
}
sort(a.begin(), a.end());
vector<bool> f(n + 1);
f[0] = true;
for (int i = 0; i < a.size(); i ++ )
{
for (int j = n; j >= a[i]; j -- )
{
if (!f[j] && f[j - a[i]]) f[j] = true;
}
}
cout << (f[n] ? "YES\n" : "NO\n");
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
}
ATC abc351E Jump Distance Sum
因为坐标系斜着计算困难,所以把移动步数全部换成水平or垂直的
也就是将坐标系旋转45度,并把坐标变为原来的 2 \sqrt{2} 2 倍
原来的 ( x , y ) (x,\ y) (x, y) 全部变成了 ( x + y , x − y ) (x+y,\ x-y) (x+y, x−y)
移动规则变成了可以向上下左右移动 2 个单位长度,也就是坐标奇偶性相同的才能互相达到
之后计算曼哈顿距离即可
注意因为我们将坐标轴变成 2 \sqrt{2} 2 倍了,所以最后答案要除以 2
#include <bits/stdc++.h>
using namespace std;
#define int long long
using i64 = long long;
typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;
const int N = 10;
const int maxn = 1e6 + 10;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;
void solve()
{
int n;
cin >> n;
vector<int> v[4];
for (int i = 0; i < n; i ++ )
{
int x, y;
cin >> x >> y;
if ((x + y) % 2 == 0)
{
v[0].push_back(x + y);
v[1].push_back(x - y);
}
else
{
v[2].push_back(x + y);
v[3].push_back(x - y);
}
}
for (int i = 0; i < 4; i ++ ) sort(v[i].begin(), v[i].end());
int ans = 0;
for (int i = 0; i < 4; i ++ )
{
int tmp = 0;
for (int j = 1; j < v[i].size(); j ++ ) tmp += v[i][j] - v[i][0];
for (int j = 1; j < v[i].size(); j ++ ) ans += tmp, tmp -= (v[i].size() - j) * (v[i][j] - v[i][j - 1]);
}
cout << ans / 2 << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
}