牛客多校2023 第二场

依旧是随便写点东西(

D

根据sample input猜测从后往前贪心即可

#include <bits/stdc++.h>
using namespace std;
int N,M;
int T;
bool vis[5005];
int a[2005][2005];
int main(){
    cin >> T;
    while (T--){
        int N,M,K;
        cin >> N >> M >> K;
        for (int i = 1 ; i <=N ; i ++)
            for (int j = 1 ; j <= M ; j ++)
                cin >> a[i][j];
        vector<int> nw;
        memset(vis,false,sizeof(vis));
        for (int v = K ; v ; v --){
            int i = v % N;
            if (i == 0) i = N; 
            int pos = -1;
            for (int j = 1 ; j <= M ; j ++){
                if (!vis[j]){
                    if (pos == -1 || a[i][j] >= a[i][pos])
                        pos = j;
                }
            }
            if (pos != -1){
                nw.push_back(pos);
                vis[pos] = true;
            }
        }
        sort(nw.begin(),nw.end());
        for (auto v : nw)
            cout << v << " ";
        cout << endl;
    }
    return 0;
}

E

签到题.jpg

#include <bits/stdc++.h>
#define ll long long
using namespace std;
long long T,x;
int main(){
    cin >> T;
    while (T--){
        cin >> x;
        ll t = 1;
        bool flag = false;
        for (int i = 1 ; i <= 18 ; i ++,t*=10){
            ll aa = x*t;
            if (aa > 1e18) break;
            ll sq = ceil(sqrt(aa));
            if (floor(sq * sq / t) == x){
                flag = true;
                cout << sq  << '\n';
                break;
            }
        }
        if (!flag) cout << "-1\n";
    }
    return 0;
}

F

先把问题转化成一个三维路径问题,不能碰到走过的点

然后不难发现,其实一个必败态非常难构造,一个点非常难被困

所以大胆猜测,所有的$n^3$个点都会被遍历到

考虑两个人的行动方式

$(r,g,b) =>(r+1,g,b)$等

会发现$r+g+b$的奇偶性对于先/后手来说都不变

于是其实只需要统计$r+g+b$为奇/偶的时候谁是那个多$1$的即可

即$n^3 % 2 == (r+g+b)%2$

#include<bits/stdc++.h>
using namespace std;
int T;
long long t;
int main(){
    cin >> T;
    while (T--){
        int N,r,g,b;
        cin >> N >> r >> g >> b;
        if(N&1 == (r+g+b) %2){
            cout << "Bob\n";
        }
        else cout << "Alice\n";
    }
    return 0;
}

G

 

我想的是个$PAM$

但是学弟似乎写了个结论+魔改马拉车?

#include<stdio.h>    
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>

using namespace std;

const int N = 1000010;

char rev[256];
char c[N], s[N];
int n, cnt;
int mid, mr;

bool jg(char a, char b){
    if(b == rev[a]) return true;
    return false;
}

void init(){
    for(int i = 0; i < 256; i ++) rev[i] = 1;

    rev['b'] = 'q';
    rev['d'] = 'p';
    rev['p'] = 'd';
    rev['q'] = 'b';
    rev['n'] = 'u';
    rev['u'] = 'n';
    rev['o'] = 'o';
    rev['s'] = 's';
    rev['x'] = 'x';
    rev['z'] = 'z';
    rev['#'] = '#';
}

void build(){
    s[++ cnt] = '~', s[++ cnt] = '#';
    for(int i = 1; i <= n; i++){
        s[++ cnt] = c[i];
        s[++ cnt] = '#';
    }

    s[++ cnt] = '!';
    s[cnt + 1] = '\0';
}


void solve(){
    scanf("%s", c + 1);
    n = strlen(c + 1);

    mid = mr = cnt = 0;

    build();

    int start = 2;
    vector<int> p(cnt + 10);
    for(int i = 2; i < cnt; i ++){
        if(i <= mr) p[i] = min(p[mid * 2 - i], mr - i + 1);
        else p[i] = -1;

        while(jg(s[i - p[i] - 1], s[i + p[i] + 1])) p[i] ++;

        if(i + p[i] - 1 > mr) {
            mr = i + p[i] - 1;
            mid = i;
        }

        if(p[i] > 0 && i - p[i] <= start)    {
            s[i + p[i] - 1] = '~';
            start = i + p[i];
            i = i + p[i] - 1;
        }
    }

    if(start == cnt - 1) puts("Yes");
    else puts("No");

}

int main(){
    // ios::sync_with_stdio(false);
    // cin.tie(nullptr);

    init();

    int T;
    cin >> T;
    while(T --){
        solve();
    }

    return 0;
}

H

两个操作很复杂,考虑怎么统一成一个

根据计算机组成原理的知识:

假设一个数的补码为$x$

反码为$~x$

$~x$+$x$ = $0xffffffff$

而补码下$0xffffffff$ = $-1$

所以x+~x=-1

==>~x=-x-1

统一成功.jpg(一点小小的408震撼)

然后就可以线段树维护矩阵来优化啦(

但是可以有个更简洁的写法

首先我们可以明确:

答案的表达形式一定是$(-1)^k * x + b$

其中$k$是$[l,r]$中$A$的数量(因为要取这么多次反)

然后考虑$b$怎么处理

会考虑前缀

假设$b_{l-1}$和$b_r$分别表示算到$l-1$和$r$的时候的$b$

那么对于$b_{l-1}$来说,它后面本来要经历$k$次翻转,然后贡献到$b_r$中

这里我们需要扔掉$b_{l-1}$的贡献,所以如果$k$为奇数的话

因为它后面经历了奇数次翻转,所以加入答案的贡献是$-b_{l-1}$

所以我们算的时候要把这部分贡献补回来,所以是$+b_{l-1}$

偶数亦然

然后就结束啦(

#include <bits/stdc++.h>
#define ll long long
#define int long long
using namespace std;
int N,Q;
const int mx = 2e5+10;
string ss;
int Sum[mx];
int Pre[mx];
string x;
signed main(){
    cin >> N >> Q;
    cin >> ss;
    int Len = ss.length();
    for (int i = 1 ; i <= Len ; i ++){
        if (ss[i-1] == 'A'){ 
            Sum[i] = Sum[i-1] * (-1) - 1;
            Pre[i] = Pre[i-1] + 1;
        }
        else {
            Sum[i] = Sum[i-1] + 1;
            Pre[i] = Pre[i-1];
        }
    }
    int lasans = 0;
    while (Q--){
        int l,r;
        cin >> l >> r;
        int L,R;
        L = min(((lasans^l)%N)+1,(((lasans^r))%N)+1);
        R = max(((lasans^l)%N)+1,(((lasans^r))%N)+1);
        l = L , r = R;
        int Cnt = Pre[r] - Pre[l-1];
        int Sign = 0;
        if (Cnt & 1ll) Sign = 1;
        else Sign = -1;
        int Sign1 = 0;
        if (Cnt & 1) Sign1 = -1;
        else Sign1 = 1;
        cin >> x;
        int Len = x.length();
        long long xx = 0;
        for (int i = 0 ; i < Len ; i ++)
            xx  = xx*2ll + x[i] - '0';
        ll P = (1ll<<(Len));
        ll Sum1 = Sign * Sum[l-1] + Sum[r];
        long long ans = ((Sign1 * xx)%P + Sum1%P)%P;
        if (ans < 0) 
            ans = (ans + P)%P;
        string ss1 = "";
        lasans = ans;
        for (int i = 0 ; i < Len ; i ++){
            if (ans & (1ll<<i)) ss1 = '1' + ss1;
            else ss1 = '0' + ss1;
        }
        cout << ss1 << '\n';
    }
    return 0;
}

 

posted @ 2023-07-23 21:27  si_nian  阅读(31)  评论(0)    收藏  举报