codeforces round943 div3

这个div3真是一言难尽...

A maximize

题目:b38b7120ce2c49a68cadcf2d04db0686.png

思路:
无脑暴力

代码:

#include <iostream>

using namespace std;

int gcd(int a, int b) {
    return b? gcd(b, a % b): a;
}

void solve() {
    int x;
    cin >> x;
    int ma = 0;
    int ans = 1;
    for(int i = 1; i < x; i ++ ) {
        if(gcd(x, i) + i > ma) {
            ma = gcd(x, i) + i;
            ans = i;
        }
    }
    cout << ans << endl;
}

int main() {
    int t;
    cin >> t;
    while(t -- ) {
        solve();
    }
    return 0;
}

B prefiquence

题目:9fef5332ce054fceb5578cdd0482296e.png

思路:二分板子题.. 据说可以双指针,抽时间补一下

代码:

#include <iostream>

using namespace std;

const int N = 2e5 + 10;

int n, m;
string a, b;

bool check(int k) {
    int i = 1, j = 1;
    while(i <= k && j <= m) {
        if(a[i - 1] == b[j - 1]) i ++;
        j ++;
    }
    if(i == k + 1) return true;
    return false; 
}

void solve() {
    cin >> n >> m >> a >> b;

    int l = 0, r = m;
    while(l < r) {
        int mid = l + r + 1 >> 1;
        if(check(mid)) l = mid;
        else r = mid - 1;
    }
    cout << l << endl;
}

int main() {
    int t;
    cin >> t;
    while(t -- ) {
        solve();
    }
    return 0;
}

C  Assembly via Remainders

题目:1f4f7b9998c0479bad746cda91e0bbf6.png

思路:构造模拟 xi = ai % ai - 1 并且要满足ai > xi + 1由%运算性质可知, ai = k * ai - 1 + xi 让k从1开始遍历,直到使得ai>xi + 1。

代码:

#include <iostream>

using namespace std;

const int N = 510;

int a[N], ans[N];
int n;

void solve() {
    cin >> n;
    for(int i = 2; i <= n; i ++ ) cin >> a[i];
    ans[1] = a[2] + 1;
    for(int i = 2; i <= n; i ++ ) {
        int x = ans[i - 1] + a[i];
        while(x <= a[i + 1]) {
            x += ans[i - 1];
        }
        ans[i] = x;
    }
    for(int i = 1; i <= n; i ++ ) cout << ans[i] << " ";
    cout << endl;
}

int main() {
    int t;
    cin >> t;

    while(t -- ) {
        solve();
    }
    return 0;
}

D permutation game

题目:d7a8a3f847884a6fa6a4dbc3f1cf2ace.png

思路:由移动规则可知,最终玩家的路径肯定会形成一个最大结点数为n的自环,遍历每个玩家的自环,找到玩家各自的分数最大值

问题:为什么会爆long long????

代码:

#include <iostream>
#include <cstring>

using namespace std;

const int N = 2e5 + 10;

int n, k, pb, ps;
int p[N], a[N];
bool st[N];

unsigned long long get(int k, int cur) {
    memset(st, 0, sizeof st);
    unsigned long long score = 0;
    unsigned long long scr = 0;
    while(!st[cur] && k) {
        st[cur] = true;
        score = max(score, scr + (unsigned long long)a[cur] * k);
        scr += a[cur];
        cur = p[cur];
        k --;
    }
    return score;
}

void solve() {
    cin >> n >> k >> pb >> ps;
    for(int i = 1; i <= n; i ++ ) cin >> p[i];
    for(int i = 1; i <= n; i ++ ) cin >> a[i];
    unsigned long long scoreB = get(k, pb);
    unsigned long long scoreS = get(k, ps);
    if(scoreB == scoreS) cout << "Draw" << endl;
    else if(scoreB > scoreS) cout << "Bodya" << endl;
    else cout << "Sasha" << endl;
}

int main() {
    int t;
    cin >> t;
    while(t -- ) {
        solve();      
    }
    return 0;
}

E. Cells Arrangement

问题:4d3a420d53ae4124ba6b39559dcb6d65.png

这道模拟..不想评价..

F equal xor segments

问题:aae46413ceff4e589d62732c02fc48d9.png思路:这道题挺抽象的..相信很多人都能想到前缀和优化异或,然后就不知道怎么处理了...根据异或性质如果有五段分别为x x x x x由于x ^ x = 0, x ^ 0 = x,因此所有奇数数段都可以继续合并成3段(x ^ x ^ x = x | x | x),同样的,偶数数段可以继续合并成两段,因现在只需要判断是否可以找到合法的两段或者三段。对于分成两段的情况,若可以找到任意的i(l <= i < r)使得sum[l - 1] ^ sum[i] == sum[r] ^ sum[i]即判断sum[l - 1] 是否等于 sum[r]这种情况可以在o(1)的时间复杂度内查询。对于分成三段的情况,存在i, j使得sum[i] ^ sum[l - 1] == sum[j] ^ sum[i] == sum[r] ^ sum[j]化简得sum[l - 1] == sum[j], sum[r] == sum[i]并且i < j 并且j < r。对这里的处理也是一大难题,我赛时也止步于此,答案的二分我是真的没有想到。答案中用map<int, vector<int>>存储了前缀异或可能值的下标,由于存储时是顺序存储的,因此下标满足二分条件,只要二分出答案并且判断二分出的答案下标是否满足条件,即可判断这种情况是否成立

problem:e2dc28c16acf42528dbb3ce873f34230.png

8c8c7c5054df46d09442b99553cc2bf3.png这两段代码有什么区别????

代码:

#include <algorithm>
#include <iostream>
#include <map>
#include <vector>

using namespace std;

const int N = 2e5 + 10;

int a[N];
int n, q;

void solve() {
    map<int, vector<int>> ma;
    ma[0].push_back(0);
    cin >> n >> q;
    for(int i = 1; i <= n; i ++ ) {
        cin >> a[i];
        a[i] ^= a[i - 1];
        ma[a[i]].push_back(i);
    }

    while(q -- ) {
        int l, r;
        cin >> l >> r;
        if(a[r] == a[l - 1]) {
            cout << "YES" << endl;
            continue;
        }

        auto &A = ma[a[r]];
        auto &B = ma[a[l - 1]];
        int ll = 0, rr = A.size() - 1;
        while(ll < rr) {
            int mid = ll + rr >> 1;
            if(A[mid] >= l) rr = mid;
            else ll = mid + 1;
        }
        int judge = ll;
        ll = 0, rr = B.size() - 1;
        while(ll < rr) {
            int mid = ll + rr + 1 >> 1;
            if(B[mid] < r) ll = mid;
            else rr = mid - 1;
        }
        if(A[judge] < B[ll]) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
    cout << endl;
}

int main() {
    int t;
    cin >> t;
    while(t -- ) {
        solve();
    }
    return 0;
}

G division + lcp(easy version)

问题:077b618f5def4d9485791595030abdb2.png

思路:二分 + 字符串处理 字符串处理在check中比赛时忘了kmp怎么写了,写的暴力tle了....

tle代码:

bool check(int a) {
    int cnt = 1;
    string pre = str.substr(0, a);
    int idx = a;
    for(; idx < n - a + 1; ) {
        if(str.substr(idx, a) == pre) {
            cnt ++;
            idx = idx + a;
        } else idx ++;
    }
    if(cnt >= l) return true;
    return false;
}

kmp ac代码:

#include <iostream>

using namespace std;

const int N = 2e5 + 10;

int n, l, r;
char str[N], p[N];
int ne[N];

bool check(int a) {
    int cnt = 0;
    for(int i = 1; i <= a; i ++ ) p[i] = str[i];
    for(int i = 2, j = 0; i <= a; i ++ ) {
        while(j && p[i] != p[j + 1]) j = ne[j];
        if(p[i] == p[j + 1]) j ++;
        ne[i] = j;
    }

    for(int i = 1, j = 0; i <= n; i ++ ) {
        while(j && str[i] != p[j + 1]) j = ne[j];
        if(str[i] == p[j + 1]) j ++;
        if(j == a) {
            cnt ++;
            j = 0;
        }
    }
    return cnt >= l;
}

void solve() {
    cin >> n >> l >> r;
    for(int i = 1; i <= n; i ++ ) cin >> str[i];
    int ll = 0, rr = n / r;
    while(ll < rr) {
        int mid = ll + rr + 1 >> 1;
        if(check(mid)) ll = mid;
        else rr = mid - 1;
    }
    cout << ll << endl;
}

int main() {
    int t;
    cin >> t;
    while(t -- ) {
        solve();
    }
    return 0;
}

同样的,字符串哈希也可以很好的解决这个问题

代码

#include <iostream>
#include <vector>
#include <cstring>
 
using namespace std;
 
const int P = 131;
const int N = 2e5 + 10;
 
int n, ll, rr;
char str[N];
unsigned long long h[N], p[N];
 
unsigned long long get(int l, int r) {
    return h[r] - h[l - 1] * p[r - l + 1];
}
 
bool check(int mid) {
    int i = 1;
    int cnt = 0;
    while(i <= n - mid + 1) {
        unsigned long long judge = get(1, mid);
        if(get(i, i + mid - 1) == judge) {
            i += mid;
            cnt ++;
        } 
        else i ++;
    }
    return cnt >= ll;
}
 
void solve() {
    cin >> n >> ll >> rr;
    p[0] = 1;    
    for(int i = 1; i <= n; i ++ ) cin >> str[i];
    for(int i = 1; i <= n; i ++ ) {
        p[i] = p[i - 1] * P;
        h[i] = h[i - 1] * P + str[i] - '0';
    }
    int l = 0, r = n / ll;
    while(l < r) {
        int mid = l + r + 1 >> 1;
        if(check(mid)) l = mid;
        else r = mid - 1;
    }
    cout << l << endl;
}
 
int main() {
    int t;
    cin >> t;
    while(t -- ) {
        solve();
    }
}

这个代码在第82个数据点wa了..这里应该是哈希被卡数据了...

本来以为F要用z函数写,还专门去学了学z函数,发现F题的核心并不是z函数....

z函数写法

#include <iostream>
#include <cstring>
 
using namespace std;
 
const int N = 2e5 + 10;
 
int n, ll, rr;
char str[N];
int z[N];
 
bool check(int mid, int a) {
    int cnt = 0;
    for(int i = 1; i <= n; i ++ ) {
        if(z[i] >= mid) {
            cnt ++;
            i += mid - 1;
        }
    }
    return cnt >= a;
}
 
void solve() {
    cin >> n >> ll >> rr;
    memset(z, 0, sizeof z);
    for(int i = 1; i <= n; i ++ ) cin >> str[i];
    
    int boxl = 0, boxr = 0;
    z[1] = n;
    for(int i = 2; i <= n; i ++ ) {
        if(i > boxr) {//i在zbox外
            while(i + z[i] <= n && str[i + z[i]] == str[1 + z[i]]) z[i] ++;//在多测时一定要加i + z[i] <= n的条件,否则会被上一个数据影响
            boxl = i, boxr = i + z[i] - 1;
        } else if(z[i - boxl + 1] <= boxr - i) z[i] = z[i - boxl + 1];
        else {
            z[i] = boxr - i;
            while(i + z[i] <= n && str[i + z[i]] == str[1 + z[i]]) z[i] ++;
            boxl = i, boxr = i + z[i] - 1;
        }
    } 
    
    for(int i = ll; i <= rr; i ++ ) {
        int l = 0, r = n / i;
        while(l < r) {
            int mid = 1 + l + r >> 1;
            if(check(mid, i)) l = mid; 
            else r = mid - 1;
        }
        cout << r << " ";
    }
    cout << endl;
}
 
int main() {
    int t;
    cin >> t;
    while(t -- ) {
        solve();
    }
}

F diversion + lcp(hard version) 

题目:5161ec6ccc7b41fe9b9739352d519b3d.png

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值