Codeforces Round #650 (Div. 3) C、D、E

题目
题意:n张桌子排成一排,1字符代表该桌子有人,0字符代表空桌,相邻两个人之间的距离不能少于k。
给出一组字符数组表示当前n张桌子的状态(保证该状态符合题意),问n张桌子还能最多坐几人。
解法:以边界和‘1’为分界线,考虑每一段连续空桌数目可坐几人.

const int maxn = 2e5+9;
char s[maxn];
void solve(){
    int n , k ;
    cin >> n >> k;
    scanf("%s" , s+1);
    vector<int>v;
    v.pb(0);
    rep(i , 1 , n){
        if(s[i] == '1'){
            v.pb(i);
        }
    }
    v.pb(n+1);
    int ans = 0 ;
    if(size(v) == 2){//如果没有1
        ans = (n+k) / (k+1);//向上取整
        if(!ans) ans++;
        cout << ans << endl;
        return ;
    }
    rep(i , 1 , size(v)-1){
        int cnt = v[i] - v[i-1] - 1 ;
        if(i != 1 && i != size(v)-1){//两边边界都为1。
            ans += (cnt - k) / (k+1);
        }else{
            ans += cnt / (k+1);//一边边界为1.
        }
    }
    cout << ans << endl;
}

D题意:给出一个小写字母字符串s,和一个长为n的数组b,问能否从s字符串挑选出n个字母组成一个字符串,该字符串满足:b[i] 等于比第i个字母大所有字符的距离之和。
解法:b[i]一定存在值为0,因为最大字母的b[i]=0,所以跟据最大字母值模拟往前推。

const int maxn = 50+9;
char s[maxn] , str[maxn];
int b[maxn];
int cnt[maxn];
int vis[maxn];
int n ;
void work(int x){
    rep(i , 1 , n){
        if(b[i]){
            b[i] -= abs(i-x);
        }
    }
}
void solve(){
    ME(vis , 0);
    ME(cnt , 0);
    scanf("%s" , s+1);
    rep(i , 1 , strlen(s+1)){
        cnt[s[i]-'a']++;//统计字母
    }
    cin >> n ;
    rep(i , 1 , n){
        cin >> b[i];
    }
    while(true){
        int flag = 1 ;
        vector<int>v;
        rep(i , 1 , n){
            if(!b[i] && !vis[i]){//找出当前所有0值
                v.pb(i);
                vis[i] = 1;
                flag = 0;
            }
        }
        int index ;
        red(i , 25 , 0){//找一个最大字母
            if(cnt[i]){
                if(cnt[i] >= size(v)){//该字母个数需要大于0值个数
                    index = i ;
                    cnt[i] = 0;//销毁该字母
                    break;
                }else{
                    cnt[i] = 0;//销毁
                    continue;
                }
            }
        }
        for(auto i : v){//修改所有比该字母的b[i]
            work(i);
            str[i] = index+'a' ;
        }
        if(flag) break;
    }
    rep(i , 1 , n){
        cout << str[i] ;
    }
    cout << endl;
}

E题意:有一个n个字符的字符串,要求使用其中字符构造一个环(不必全部都用)。定义一个环是k美的:它转k次仍是原样。现在给你k,要求最长的k美环的长度.
解法:考虑k的因子,如果k的因子满足k美,那么一定也是k美,枚举k因子作为循环节,二分最大周期数,答案即为最大的循环节*周期数.

int n , m ;
char s[maxn];
int cnt[27];
bool check(int x , int y){
    rep(i , 0 , 25){
        y -= cnt[i] / x ;
    }
    return y <= 0;//可以构造x周期的y循环节环
}

void solve(){
    int n , k ;
    cin >> n >> k;
    scanf("%s" , s+1);
    ME(cnt , 0);
    rep(i , 1 , n){
        cnt[s[i]-'a']++;
    }
    int ans = 1 ;
    rep(i , 1 , k){
        if(k % i == 0){//枚举k因子,即循环节长度
            int l = 1 , r = n ;//二分查找最大周期数
                int mid = (l + r) >> 1 ;
                if(check(mid , i)){//周期为mid,循环节长为i
                    l = mid+1;
                }else{
                    r = mid-1 ;
                }
            }
            ans = max(ans , r*i);
        }
    }
    cout << ans << endl;
}

另一种思路

const int maxn = 20+9;
int cnt[maxn];

void solve(){
    int n , k ;
    cin >> n >> k ;
    string s ;
    cin >> s;
    ME(cnt , 0);
    rep(i , 0 , n-1){
        cnt[s[i]-'a']++;
    }
    int ans = 0 ;
    rep(i , 1 , n){//枚举
        int nc = gcd(i , k);
        int percyc = i / nc ;//循环节长度
        rep(j , 0 , 25){
            nc -= cnt[j] / percyc;//该字母能填充的循环节长
        }
        if(nc <= 0) ans = i ;//如果大于循环节长度就符合。
    }
    cout << ans << endl;
}

猜你喜欢

转载自www.cnblogs.com/nonames/p/13167963.html
今日推荐