Codeforces CROC 2016 - Elimination Round

C. Enduring Exodus

从左到右枚举人住的房间,牛住的房间不断往后推。

#include <cstdio>
#include <iostream>
#include <algorithm>


using namespace std;

char str[100010];

int Next[100010];

int calc(int pos,int l,int r){
    return max(r-pos,pos-l);
}

int main(){
    int n,k;
    cin>>n>>k;
    scanf("%s",str);
    for(int i=n-2;i>=0;i--){
        if(str[i+1]=='0'){
            Next[i]=i+1;
        }else{
            Next[i]=Next[i+1];
        }
    }
    int pos = 0;
    while(str[pos]!='0'){
        pos++;
    }
    int l = pos;
    int r = pos+1;
    int cnt = 0;
    while(1){
        if(str[r]=='0'){
            cnt++;
        }
        if(cnt==k)break;
        r++;
    }
    int ans = calc(pos,l,r);

    for(int i=Next[pos];i!=0;i=Next[i]){
        if(i>r){
            r=Next[r];
            l=Next[l];
        }
        if(r==0)break;
        ans = min(ans,max(r-i,i-l));
        while(i-l>r-i){
            if(r==0)break;
            ans = min(ans,max(r-i,i-l));
            r=Next[r];
            l=Next[l];
            if(r==0)break;
            ans = min(ans,max(r-i,i-l));
        }
        if(r==0)break;
    }
    cout<<ans<<endl;
    return 0;
} 

D. Robot Rapping Results Report

不妨把胜负当成点的出度和入度来看,读数据的时候维护点的度,当出现有一个点只有出度,一个点只有入度,其他的点均有出度和入度时,那两个特别的点肯定是最大的和最小的,删除顺序已知的点……如此循环直到只剩下0或1个点为止,就能认为是有序的了。

#include <bits/stdc++.h>
#include <unordered_set>

using namespace std;

const int maxn = 100010;

vector<int> win[maxn];
vector<int> lose[maxn];

int l[maxn];
int r[maxn];

int lcnt = 0;
int rcnt = 0;
int lrcnt = 0;

bool ban[maxn];

set<int> Set;

int main(){
    int n,m;
    int MAX = 0;
    int MIN = 0;

    cin>>n>>m;

    for(int i=1;i<=n;i++){
        Set.insert(i);
    }

    int N=n;

    int ans = -1;
    for(int i=1;i<=m;i++){
        int u,v;
        scanf("%d%d",&u,&v);

        if(ban[u] || ban[v])continue;
        win[u].push_back(v);
        lose[v].push_back(u);
        l[u]++;
        r[v]++;
        if(l[u]==1){
            lcnt++;
            if(r[u]){
                lrcnt++;
                Set.erase(u);
            }
        }
        if(r[v]==1){
            rcnt++;
            if(l[v]){
                lrcnt++;
                Set.erase(v);
            }
        }

        while(lrcnt == N-2 && lcnt==N-1 && rcnt==N-1){
            rcnt--;
            lcnt--;
            auto it = Set.begin();
            int winner = *it;
            it++;
            int loser = *it;
            Set.clear();
            if(l[loser]){
                swap(winner,loser);
            }

            ban[winner] = 1;
            ban[loser] = 1;
            for(int tt:win[winner]){
                if(ban[tt])continue;
                r[tt]--;
                if(r[tt]==0){
                    rcnt--;
                    if(l[tt]){
                        lrcnt--;
                        Set.insert(tt);
                    }
                }
            }

            for(int tt:lose[loser]){
                if(ban[tt])continue;
                l[tt]--;
                if(l[tt]==0){
                    lcnt--;
                    if(r[tt]){
                        lrcnt--;
                        Set.insert(tt);
                    }
                }
            }

            N-=2;
        }
        if(N<2){
            ans = i;
        }
    }

    cout<<ans<<endl;
    return 0;
} 

E. Intellectual Inquiry

考虑某个字符串, dp(i) 表示以字符 i 结尾的子序列的个数,那么在字符串后面添加字符j时, dp(j)=1+dp ,无论 j 是那个字符,dp(j)的结果都是一样的,所以我们总是可以选择 dp(j) 最小的那个 j 使得增益最大。又由于经过了取模,不好直接找到最小值,我们可以发现字符j如果出现得越早, dp(j) 肯定越小。

#include <bits/stdc++.h>
#include <unordered_map>

using namespace std;

#define ll long long 

char str[1000010];

ll dp[26];

const int mod = 1e9+7;

int lastAppear[26];

int main(){
    memset(lastAppear,-1,sizeof(lastAppear));
    int n,k;
    cin>>n>>k;
    scanf("%s",str);
    int m = strlen(str);

    ll sum = 0;

    for(int i=0;i<m;i++){
        lastAppear[str[i]-'a'] = i;
        ll tmp = dp[str[i]-'a'];
        dp[str[i]-'a'] = sum+1;
        dp[str[i]-'a'] %= mod;
        sum = 0;
        for(int j=0;j<k;j++){
            sum+=dp[j];
        }
    }


    for(int i=0;i<n;i++){
        // find min
        int MIN = 1e9;
        int minchar=0;
        for(int j=0;j<k;j++){
            if(lastAppear[j]<MIN){
                MIN = lastAppear[j];
                minchar = j;
            }
        }

        lastAppear[minchar] = m+i;
        ll tmp = dp[minchar];
        dp[minchar] = sum+1;
        dp[minchar] %= mod;
        sum = 0;
        for(int j=0;j<k;j++){
            sum+=dp[j];
        }
    }

    ll ans = 1;
    for(int i=0;i<k;i++){
        ans+=dp[i];
        ans%=mod;
    }

    cout<<ans<<endl;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值