自学内容网 自学内容网

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} pi1操作
得出结论:找到循环节,然后对每个数进行 2 K − 1 2^K-1 2K1次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..Sk1的操作数最少为多少


在一堆字符串里做编辑,第一感觉就是字典树
按顺序插入,插入的时候去看每个位置到之前的叶子节点最短是多少,这就是先删除到插入位置再增加字符的最小代价
动态开树居然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)!