牛客第三场多校

 J题:

由于字符串可以无限往后复制,而我们只需要求最开始的长度为n的比赛结果。复制字符串达到可以使得第一个大场分出胜负即可,之后记录从某个点开始比赛的第一场结果,以及,这场结束后的下一场开始的下标。就可以在初始字符串无限循环下去,得到任意场结果。

再利用倍增,得到从某点开始,2的任意次方局后a赢得场次,以及2的任意次方局后,下场开始的下标,就可以nlogn得到结果了。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
const ll inf = 1e18;
long long int mod = 1000000007;
const int maxN = 2e5 + 10;
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);


int main() {
    IOS
    int n,a,b;
    cin>>n>>a>>b;
    string t,tmp;
    cin>>t;
    tmp=t;
    int len=(int)t.size();
    while(tmp.size()<len+2*a){
        tmp+=t;
    }
    vector<int>winner(n+1),next(n+1);
    int r,l=0;
    int cnt=0;
    for(r=0;r<tmp.size()&&l<n;r++){
        if((tmp[r]-'0')==1)
            cnt++;
        if(r-l+1-cnt==a) {
            winner[l] = 0;
            if (tmp[l] == '1') {
                cnt--;
            }
            next[l] = (r + 1) % n;
            l++;
            r--;
            if((tmp[r+1]-'0')==1)
                cnt--;
        }
        if(cnt==a){
            winner[l]=1;
            if(tmp[l]=='1'){
                cnt--;
            }
            next[l]=(r+1)%n;
            l++;
            r--;
            if((tmp[r+1]-'0')==1)
                cnt--;
        }
    }
    vector<int>lg(2e5+10);
    lg[1]=0;
    for(int i=2;i<=2e5;i++){
        lg[i]=lg[i/2]+1;
    }
    vector<vector<int>>f(n+1,vector<int>(30)),g(n+1,vector<int>(30));
    for(int i=0;i<n;i++){
        f[i][0]=(winner[i]==1);
        g[i][0]=next[i];
    }
    for(int j=1;j<30;j++){
        for(int i=0;i<n;i++){
            f[i][j]=f[i][j-1]+f[g[i][j-1]][j-1];
            g[i][j]=g[g[i][j-1]][j-1];
        }
    }
    vector<int>ans(n+1);
    for(int i=0;i<n;i++){
        int exp=lg[b];
        int cur=(int)pow(2,exp);
        int now=0;
        int pos=i;
        while(cur<=2*b-1){
            now+=f[pos][exp];
            if(now>=b){
                ans[i]=1;
                break;
            }
            if(cur-now>=b){
                ans[i]=0;
                break;
            }
            pos=g[pos][exp];
            exp=lg[2*b-1-cur];
            cur+=(int)pow(2,exp);
        }
    }
    for(int i=0;i<n;i++){
        cout<<ans[i];
    }
    cout<<endl;
    return 0;
}

A题:

每个人需要先过河到对岸,减少一点体力。之后如果他的体力大于等于2,就可以划船一个来回,接R-L个人过来,被接过来的人和最开始去河对岸的人都一样,都是去掉了一点体力,之后看能不能进行来回。所以我们计算所有人过去需要的来回次数total,每个体力减少1,再除以二,并和总的需要的来回次数取最小值,得到其能走的来回次数ai。每次需要L个人来回,即L*total,ai总和大于等于L*total即可以成功。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int infmin = 0xc0c0c0c0;
const int infmax = 0x3f3f3f3f;
const int maxn = 5e5 + 10;

int h[maxn];
ll tranRound[maxn]; // 每个人的有效运输次数

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int n, L, R;
    cin >> n >> L >> R;

    int reuseableCnt = 0;  // 耐力值大于2的步行者数量
    for (int i = 1; i <= n; i++) {
        cin >> h[i];
        if (h[i] > 2) {
            reuseableCnt++;
            tranRound[i] = (h[i] - 1) / 2;
        }
    }

    // 一遍过
    if (n <= R) {
        cout << "Yes";
        return 0;
    }

    // 不能一遍过的情况下,没有足够的人回来继续接人
    if (reuseableCnt < L) {
        cout << "No";
        return 0;
    }

    ll wholeTrans = (n - R - 1) / (R - L) + 1;  // 需要的完整运输次数 (-1是为了上取整)
    ll wholeNum = wholeTrans * L;  // 需要的总操作人数

    for (int i = 1; i <= n; i++) {
        if (h[i] > 2) {
            wholeNum -= min(tranRound[i], wholeTrans);
        }
    }

    if (wholeNum <= 0)
        cout << "Yes";
    else
        cout << "No";

    return 0;
}

D题 

将两个数都相等的牌放在优先队列里,使他们交替排放,优先选数量多的牌。剩下的两个数不等的骨牌它们之间是一定可以排在一起的。如果优先队列里最后剩下一种牌没有排完,则需要选择那些两个元素都与这种牌不等的牌和它排在一起。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
const ll inf = 1e18;
long long int mod = 1000000007;
const int maxN = 2e5 + 10;
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);

struct Node {
    int x, y;
    int cnt;

    bool operator<(const Node rhs) const {
        return cnt < rhs.cnt;
    }
} node;

int main() {
    IOS
    int n;
//    freopen("../data/D-Dominoes!/26.in", "r", stdin);
//    freopen("output.txt", "w", stdout); // 重定向输出到 output.txt
    cin >> n;
    priority_queue<Node> q;
    map<pair<int, int>, int> tab;
    for (int i = 1; i <= n; i++) {
        int x, y;
        cin >> x >> y;
        tab[{x, y}]++;
    }
    for (auto &i: tab) {
        int x = i.first.first;
        int y = i.first.second;
        if (x == y) {
            node.cnt = i.second;
            node.x = x, node.y = y;
            q.push(node);
            i.second = 0;
        }
    }
    vector<pair<int, int>> ans;
    while (!q.empty() && q.size() != 1) {
        int x = q.top().x;
        int y = q.top().y;
        int cnt = q.top().cnt;
        if (!ans.empty() && (ans.back().first == x)) {
            node = {x, y, cnt};
            q.pop();
            int tmp = q.top().x;
            int tmp_cnt = q.top().cnt;
            ans.push_back({tmp, tmp});
            q.pop();
            tmp_cnt--;
            if (tmp_cnt >= 1) {
                q.push({tmp, tmp, tmp_cnt});
            }
            q.push(node);
        }
        ans.push_back({x, y});
        q.pop();
        cnt--;
        if (cnt >= 1) {
            node.cnt = cnt, node.x = x, node.y = y;
            q.push(node);
        }
    }
    int x = 0, y = 0;
    int cnt = 0;
    if (!q.empty()) {
        cnt = q.top().cnt;
        x = q.top().x;
        y = q.top().y;
        ans.push_back({x, y});
        cnt--;
        for (auto &i: tab) {
            if (i.first.first != x && i.first.second != x) {
                if (cnt < i.second) {
                    for (int j = 0; j < cnt; j++) {
                        ans.push_back({i.first.first, i.first.second});
                        ans.push_back({x, x});
                    }
                    i.second -= cnt;
                    cnt = 0;
                    break;
                } else {
                    for (int j = 0; j < i.second; j++) {
                        ans.push_back({i.first.first, i.first.second});
                        ans.push_back({x, x});
                    }
                    cnt -= i.second;
                    i.second = 0;
                }
            }
            if (cnt == 0) {
                break;
            }
        }
    }
    if (cnt == 0) {
        for (auto &i: tab) {
            if (i.second == 0)
                continue;
            if (i.first.first != x) {
                ans.push_back({i.first.first, i.first.second});
                i.second--;
                break;
            }
            if (i.first.second != x) {
                ans.push_back({i.first.second, i.first.first});
                i.second--;
                break;
            }
        }
        cout << "YES" << endl;
        for (int i = 0; i < ans.size(); i++) {
            cout << ans[i].first << ' ' << ans[i].second << endl;
        }
        int tmp = ans.back().second;
        for (auto i: tab) {
            if (i.second == 0)
                continue;
            if (i.first.first != tmp) {
                cout << i.first.first << ' ' << i.first.second << endl;
                i.second--;
                for(int j=0;j<i.second;j++){
                    cout << i.first.first << ' ' << i.first.second << endl;
                }
                tmp = i.first.second;
                continue;
            }
            if (i.first.second != tmp) {
                cout << i.first.second << ' ' << i.first.first << endl;
                i.second--;
                for(int j=0;j<i.second;j++){
                    cout << i.first.second << ' ' << i.first.first << endl;
                }
                tmp = i.first.first;
            }
        }
    } else {
        cout << "NO" << endl;
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值