ABC377
C
有n个马放在棋盘上,求剩下不被马攻击到的位置个数。
用set
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <unordered_map>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
ll n;
int m;
set<pair<ll, ll>> s;
int main(){
//freopen("in.txt", "r", stdin);
cin >> n >> m;
for (int i = 0; i < m; ++i) {
ll a, b;
cin >> a >> b;
s.insert({ a, b });
s.insert({ a + 2, b - 1 });
s.insert({ a + 2, b + 1 });
s.insert({ a + 1, b - 2 });
s.insert({ a + 1, b + 2 });
s.insert({ a - 1, b - 2 });
s.insert({ a - 1, b + 2 });
s.insert({ a - 2, b - 1 });
s.insert({ a - 2, b + 1 });
}
ll sub = 0;
for (auto [x, y] : s) {
if (x >= 1 && x <= n && y >= 1 && y <= n)
sub++;
}
ll ans = n * n - sub;
printf("%lld\n", ans);
return 0;
}
D
线段覆盖问题。
给了一系列线段
[
L
i
,
R
i
]
[L_i,R_i]
[Li,Ri]
求每个点l有多少点r组成的线段
[
l
,
r
]
[l,r]
[l,r]不会覆盖所有的线段,然后求和
双指针写崩了,后来发现不需要
我们可以遍历l,对每个l点来检查
如果l点是这一系列线段中的左端点,那么这一系列以l为左端点的线段其中的最小右端点-1就是r的取值上限。
但是我们从右往左遍历,如果之前的线段右端点的取值上限更小,那么也是取不到的。
比如线段有[4 6] [1 7] [1 9]
我们遍历4时r上限是5,
遍历1时r的上限不能取6,因为[1 6]会把[4 5]覆盖
维护这个上限即可。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <unordered_map>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
int f[200020];
ll ans;
int n, m;
int main(){
//freopen("in.txt", "r", stdin);
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
int l, r;
cin >> l >> r;
if (f[l] == 0) f[l] = r;
else f[l] = min(f[l], r);
}
int rgt = m + 1;
for (int i = m; i >= 1; -- i) {
if (f[i] != 0) {
rgt = min(rgt, f[i]);
}
ans += rgt - i;
}
printf("%lld\n", ans);
return 0;
}
E
给一个数列
A
A
A
每次操作将
A
i
A_i
Ai同时转换为
A
A
i
A_{A_i}
AAi,求K次操作后的数列
第一反应是矩阵快速幂,但是N太大了
我们手动来看例子:5,6,3,1,2,4 -> 2,4,3,5,6,1 -> 4,5,3,6,1,2 -> 6,1,3,2,4,5
设第一次操作的变换为p0,第二次操作为p1
首先明确每个操作有循环性
把数列从上往下排
5 6 3 1 2 4
2 4 3 5 6 1
4 5 3 6 1 2
观察p1中的2,2转换为4的操作来源于p0中6->4
我们在p1中间插一行:
5 6 3 1 2 4
2 4 3 5 6 1
6 1 3 2 4 5
4 5 3 6 1 2
即每次
p
i
p_i
pi操作都是两次
p
i
−
1
p_{i-1}
pi−1操作
得出结论:找到循环节,然后对每个数进行
2
K
−
1
2^K-1
2K−1次p0操作
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <unordered_map>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
ll n, k;
int a[200020];
bool vis[200020];
int f[200020];
int seq[200020];
vi lp[200020];
ll qpow(ll a, ll x, ll m) {
if (x == 0)
return 1;
ll temp = qpow(a, x / 2, m);
if (x & 1) {
return temp * temp % m * a % m;
}
else {
return temp * temp % m;
}
}
int main(){
//freopen("in.txt", "r", stdin);
cin >> n >> k;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
for (int i = 1; i <= n; ++i) {
int t = a[i];
while (!vis[t]) {
f[t] = a[i];
seq[t] = lp[a[i]].size();
lp[a[i]].push_back(t);
vis[t] = 1;
t = a[t];
}
}
for (int i = 1; i <= n; ++i) {
int t = f[a[i]];
ll m = lp[t].size();
int r = seq[a[i]];
int nr = (qpow(2, k, m) + (m - 1) + r) % m;
int nt = lp[t][nr];
printf("%d ", nt);
}
printf("\n");
return 0;
}
F
棋盘里面放n(<1000)个皇后,问棋盘不被攻击到的位置和。
维护四个划去的线段。比较繁琐的一个题。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <unordered_map>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
ll n;
int m;
ll ans;
unordered_map<ll, bool> row, col, dia0, dia1;
#define check(x) (x >= 1 && x <= n)
int main(){
//freopen("in.txt", "r", stdin);
cin >> n >> m;
ll ans = 0;
for (int i = 0; i < m; ++i) {
ll x, y;
cin >> x >> y;
if (!row[y]) {
set<pair<ll, ll>> dup;
for (auto [c, _] : col) {
dup.insert({ c, y });
}
for (auto [d, _] : dia0) {
ll nx = d - y;
if (check(nx))
dup.insert({ nx, y });
}
for (auto [d, _] : dia1) {
ll nx = y - d;
if (check(nx))
dup.insert({ nx, y });
}
row[y] = 1;
ll add = n - dup.size();
ans += add;
}
if (!col[x]) {
set<pair<ll, ll>> dup;
for (auto [r, _] : row) {
dup.insert({ x, r });
}
for (auto [d, _] : dia0) {
ll ny = d - x;
if (check(ny))
dup.insert({ x, ny });
}
for (auto [d, _] : dia1) {
ll ny = x + d;
if (check(ny))
dup.insert({ x, ny });
}
col[x] = 1;
ll add = n - dup.size();
ans += add;
}
ll d = x + y;
if (!dia0[d]) {
set<pair<ll, ll>> dup;
for (auto [r, _] : row) {
ll nx = d - r;
if (check(nx))
dup.insert({ nx, r });
}
for (auto [c, _] : col) {
ll ny = d - c;
if (check(ny))
dup.insert({ c, ny });
}
for (auto [d1, _] : dia1) {
if ((d + d1) % 2 == 0) {
ll nx = (d - d1) / 2, ny = (d + d1) / 2;
if (check(nx) && check(ny)) {
dup.insert({ nx, ny });
}
}
}
dia0[d] = 1;
ll add = d <= 1 + n ? d - 1 : 2 * n - d + 1;
ans += add - dup.size();
}
d = y - x;
if (!dia1[d]) {
set<pair<ll, ll>> dup;
for (auto [r, _] : row) {
ll nx = r - d;
if (check(nx))
dup.insert({ nx, r });
}
for (auto [c, _] : col) {
ll ny = d + c;
if (check(ny))
dup.insert({ c, ny });
}
for (auto [d0, _] : dia0) {
if ((d + d0) % 2 == 0) {
ll nx = (d0 - d) / 2, ny = (d0 + d) / 2;
if (check(nx) && check(ny)) {
dup.insert({ nx, ny });
}
}
}
dia1[d] = 1;
ll add = d >= 0 ? n - d : n + d;
ans += add - dup.size();
}
}
printf("%lld\n", n * n - ans);
return 0;
}
G
n个string
依次对于k=1…n
S
k
S_k
Sk可以删除一个字符或增加一个字符记为1次操作
问:
S
k
S_k
Sk修改为空或者
S
1
,
S
2
.
.
S
k
−
1
S_1,S_2..S_{k-1}
S1,S2..Sk−1的操作数最少为多少
在一堆字符串里做编辑,第一感觉就是字典树
按顺序插入,插入的时候去看每个位置到之前的叶子节点最短是多少,这就是先删除到插入位置再增加字符的最小代价
动态开树居然wa了好几次,建议静态开树(其实是我菜 )
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <unordered_map>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
const int N = 200020;
int tr[N][26], d[N];
int n;
int main(){
//freopen("in.txt", "r", stdin);
cin >> n;
int cnt = 0;
int p = 0;
memset(d, 0x3f, sizeof(d));
for (int i = 0; i < n; ++i) {
string s;
cin >> s;
int m = s.length();
int ans = m;
p = 0;
for (int j = 0; j < m; ++j) {
int idx = s[j] - 'a';
if (!tr[p][idx])
tr[p][idx] = ++cnt;
p = tr[p][idx];
ans = min(ans, m - 1 - j + d[p]);
d[p] = min(d[p], m - 1 - j);
}
printf("%d\n", ans);
}
return 0;
}
原文地址:https://blog.csdn.net/acrux1985/article/details/143615823
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!