ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Codeforces Round #584 (Div. 1 + Div. 2)

2019-09-18 23:02:47  阅读:188  来源: 互联网

标签:584 int Codeforces len while Div getchar mx dis


Contest Page

A

sol 每次选最小的,然后把它的所有倍数都删掉。
#include<bits/stdc++.h>
using namespace std;

int read(){
    int a = 0; char c = getchar(); bool f = 0;
    while(!isdigit(c)){f = c == '-'; c = getchar();}
    while(isdigit(c)){
        a = a * 10 + c - 48; c = getchar();
    }
    return f ? -a : a;
}

set < int > num;

int main(){
    int N , cnt = 0; cin >> N;
    for(int i = 1 ; i <= N ; ++i){int a; cin >> a; num.insert(a);}
    while(!num.empty()){
        ++cnt; int val = *num.begin();
        for(int i = val ; i <= 100 ; i += val)
            if(num.find(i) != num.end()) num.erase(i);
    }
    cout << cnt;
    return 0;
}

B

sol 因为$lcm(2,3,4,5)=120$,所以在所有灯都开始闪了之后$120sec$之后到达的状态一定一致。所以暴力做$>125$轮即可。
#include<bits/stdc++.h>
using namespace std;

int num[1003] , N , A[1003] , B[1003];

int main(){
    cin >> N;
    for(int i = 1 ; i <= N ; ++i){
        char c = getchar(); while(!isdigit(c)) c = getchar();
        num[i] = c - '0';
    }
    for(int i = 1 ; i <= N ; ++i) cin >> A[i] >> B[i];
    int ans = 0; for(int i = 1 ; i <= N ; ++i) ans += num[i];
    for(int i = 1 ; i <= 250 ; ++i){
        for(int j = 1 ; j <= N ; ++j)
            if(i >= B[j] && (i - B[j]) % A[j] == 0)
                num[j] ^= 1;
        int sum = 0; for(int j = 1 ; j <= N ; ++j) sum += num[j];
        ans = max(ans , sum);
    }
    cout << ans; return 0;
}

C

sol 枚举$i \in [0 , 8]$,先将$\leq i$的所有数都染$1$,然后将最后染$1$的位置之后的所有数值为$i+1$的位置染$1$,最后把剩下的数染$2$,check是否合法即可。
#include<bits/stdc++.h>
using namespace std;

int T; bool vis[200003];

int main(){
    ios::sync_with_stdio(0);
    for(cin >> T ; T ; --T){
        int L; string s; cin >> L >> s; bool getans = 0;
        for(int i = 0 ; i < 9 && !getans ; ++i){
            memset(vis , 0 , sizeof(bool) * (s.size()));
            int mx = 0 , pre = -1; bool flg = 1;
            for(int j = 0 ; j < s.size() ; ++j)
                if(s[j] - '0' <= i){
                    if(mx > s[j] - '0'){flg = 0; break;}
                    pre = j; mx = max(mx , s[j] - '0'); vis[j] = 1;
                }
            if(!flg) continue;
            for(int j = pre + 1 ; j < s.size() ; ++j)
                if(s[j] - '0' == i + 1) vis[j] = 1;
            mx = 0;
            for(int j = 0 ; j < s.size() ; ++j)
                if(!vis[j]){
                    if(mx > s[j] - '0'){flg = 0; break;}
                    mx = s[j] - '0';
                }
            if(flg){
                getans = 1;
                for(int i = 0 ; i < s.size() ; ++i) putchar(vis[i] ? '1' : '2');
            }
        }
        if(!getans) putchar('-');
        putchar('\n');
    }
    return 0;
}

D

sol 对于$a=i,b=j$连边$(i,j)$,对于每一个连通块一定是先选择一条边,然后一直选择恰好有一端被标记过的边直到所有点被标记,那么一个连通块的贡献是$sz-1$。并查集实现连通块即可。
#include<bits/stdc++.h>
using namespace std;

const int _ = 1e5 + 7;
int N , K , fa[_] , sz[_];
int find(int x){return fa[x] == x ? x : (fa[x] = find(fa[x]));}

int main(){
    cin >> N >> K; for(int i = 1 ; i <= N ; ++i) sz[fa[i] = i] = 1;
    for(int i = 1 ; i <= K ; ++i){
        int p , q; cin >> p >> q;
        p = find(p); q = find(q);
        if(p == q) continue;
        fa[p] = q; sz[q] += sz[p];
    }
    for(int i = 1 ; i <= N ; ++i) if(fa[i] == i) K -= sz[i] - 1;
    cout << K; return 0;
}

E1

sol 发现在最优情况下只有最大值最大的$n$行有意义,拿出来暴力即可。
#include<bits/stdc++.h>
using namespace std;

int read(){
    int a = 0; char c = getchar(); bool f = 0;
    while(!isdigit(c)){f = c == '-'; c = getchar();}
    while(isdigit(c)){
        a = a * 10 + c - 48; c = getchar();
    }
    return f ? -a : a;
}

#define PII pair < int , int >
int T , N , M , arr[13][2003] , mx[2003] , id[2003];

int mat[5][5] , ans;

void dfs(int x){
    if(x > N || x > M){
        int sum = 0;
        for(int i = 0 ; i < N ; ++i){
            int mx = 0;
            for(int j = 0 ; j < N ; ++j)
                mx = max(mx , mat[i][j]);
            sum += mx;
        }
        ans = max(ans , sum); return;
    }
    for(int i = 0 ; i < N ; ++i){
        for(int j = 0 ; j < N ; ++j)
            mat[(i + j) % N][x - 1] = arr[j + 1][id[x]];
        dfs(x + 1);
    }
}

int main(){
    for(cin >> T ; T ; --T){
        cin >> N >> M; ans = 0; memset(mx , 0 , sizeof(mx)); memset(mat , 0 , sizeof(mat));
        for(int i = 1 ; i <= N ; ++i){
            for(int j = 1 ; j <= M ; ++j){
                cin >> arr[i][j];
                mx[j] = max(mx[j] , arr[i][j]);
            }
        }
        for(int i = 1 ; i <= M ; ++i) id[i] = i;
        sort(id + 1 , id + M + 1 , [&](int A , int B){return mx[A] > mx[B];});
        dfs(1); cout << ans << endl;
    }
    return 0;
}

E2

F

sol 对于每条边以其编号位数为权值跑最短路,建出最短路DAG,那么每个点的答案只有可能由最短路DAG上的路径构成。

然后按照DAG拓扑序求出答案。对于每个点找到其在DAG上的所有前驱,两两比较数字串字典序大小。总串长度不长,可以通过建Trie树把每个点对应的串放上去然后求LCA比较字典序。VP的时候没想很多写了个比较麻烦的做法:

对于已求出的每个点确定其最短路转移的唯一前驱,这样就把最短路DAG变成了最短路树。那么二分第一个字符不相同的位置,然后在最短路树上倍增求出这个字符串的哈希值check,最后通过倍增得到对应位置的两个字符判断哪一个小。
#include<bits/stdc++.h>
using namespace std;

int read(){
    int a = 0; char c = getchar(); bool f = 0;
    while(!isdigit(c)){f = c == '-'; c = getchar();}
    while(isdigit(c)){
        a = a * 10 + c - 48; c = getchar();
    }
    return f ? -a : a;
}

#define PII pair < int , int >
const int _ = 1e5 + 7 , MOD = 1e9 + 7 , MOD2 = 1e9 + 9;
priority_queue < PII > q;
vector < PII > Edge[_];
int logg10[_] , dis[_] , N , M , jump[_][20] , val[_] , ans[_]; long long faid[_];

int gethash(int x , int len , int id){
    int now;
    if(len > dis[x]){now = val[x]; len -= dis[x];}
    else{
        for(int i = 19 ; i >= 0 ; --i) if(dis[jump[x][i]] >= len) x = jump[x][i];
        now = val[jump[x][0]]; len -= dis[jump[x][0]]; id = faid[x];
    }
    while(logg10[id] != len - 1) id /= 10;
    for(int i = 0 ; i < len ; ++i) now = 1ll * now * 10 % MOD2;
    return (now + id) % MOD2;
}

int getch(int x , int len , int id){
    if(len > dis[x]) len -= dis[x];
    else{
        for(int i = 19 ; i >= 0 ; --i) if(dis[jump[x][i]] >= len) x = jump[x][i];
        len -= dis[jump[x][0]]; id = faid[x];
    }
    while(logg10[id] != len - 1) id /= 10;
    return id % 10;
}

bool cmp(int p , int q , int idp , int idq){
    if(!p) return 1;
    int L = 1 , R = logg10[idp] + 1 + dis[p];
    while(L < R){
        int mid = (L + R) >> 1;
        gethash(p , mid , idp) != gethash(q , mid , idq) ? R = mid : L = mid + 1;
    }
    return getch(p , L , idp) > getch(q , L , idq);
}

void done(int x , int pre , int nid){
    ans[x] = ans[pre]; for(int i = 0 ; i <= logg10[nid] ; ++i) ans[x] = ans[x] * 10ll % MOD;
    val[x] = val[pre]; for(int i = 0 ; i <= logg10[nid] ; ++i) val[x] = val[x] * 10ll % MOD2;
    ans[x] = (ans[x] + nid) % MOD; val[x] = (val[x] + nid) % MOD2;

    faid[x] = nid; jump[x][0] = pre;
    for(int i = 1 ; jump[x][i - 1] ; ++i) jump[x][i] = jump[jump[x][i - 1]][i - 1];
}

void dijk(){
    memset(dis , 0x3f , sizeof(dis)); dis[0] = dis[1] = 0; q.push(PII(0 , 1));
    while(!q.empty()){
        PII t = q.top(); q.pop();
        if(dis[t.second] != -t.first) continue;

        int now = 0 , nid = 0;
        for(auto p : Edge[t.second])
            if(dis[p.first] + logg10[p.second] + 1 == dis[t.second])
                if(cmp(now , p.first , nid , p.second)){
                    now = p.first; nid = p.second;
                }
        
        if(now) done(t.second , now , nid);
        
        for(auto p : Edge[t.second])
            if(dis[p.first] > dis[t.second] + logg10[p.second] + 1){
                dis[p.first] = dis[t.second] + logg10[p.second] + 1;
                q.push(PII(-dis[p.first] , p.first));
            }
    }
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("in","r",stdin);
    freopen("out","w",stdout);
#endif
    N = read(); M = read(); logg10[0] = -1;
    for(int i = 1 ; i <= M ; ++i) logg10[i] = logg10[i / 10] + 1;
    for(int i = 1 ; i <= M ; ++i){
        int p = read() , q = read();
        Edge[p].push_back(PII(q , i)); Edge[q].push_back(PII(p , i));
    }
    dijk();
    for(int i = 2 ; i <= N ; ++i) printf("%d\n" , ans[i]);
    return 0;
}

G1

sol 考虑将序列分成若干个极小块,每一块中包含若干种颜色且其他块中不包含这些颜色。那么每一个块的答案就是块长减去出现次数最多的数字数量。

求出这个极小块直接从左往右扫一遍维护当前块已经出现的颜色和如果当前颜色形成极小块块长是多少就可以了。
#include<bits/stdc++.h>
using namespace std;

int read(){
    int a = 0; char c = getchar(); bool f = 0;
    while(!isdigit(c)){f = c == '-'; c = getchar();}
    while(isdigit(c)){
        a = a * 10 + c - 48; c = getchar();
    }
    return f ? -a : a;
}

const int _ = 2e5 + 3;
int arr[_] , f[_] , nxt[_] , sz[_] , N , Q , ans;
vector < int > ch[_];

int main(){
    N = read(); Q = read();
    for(int i = 1 ; i <= N ; ++i) ++sz[arr[i] = read()];
    set < int > in; int cnt = 0 , tar = 0;
    for(int i = 1 ; i <= N ; ++i){
        if(in.find(arr[i]) == in.end()){
            in.insert(arr[i]); tar += sz[arr[i]];
        }
        if(tar == ++cnt){
            int mx = 0;
            for(auto t : in) mx = max(mx , sz[t]);
            ans += tar - mx; in.clear(); cnt = 0; tar = 0; 
        }
    }
    cout << ans;
    return 0;
}

G2

H

标签:584,int,Codeforces,len,while,Div,getchar,mx,dis
来源: https://www.cnblogs.com/Itst/p/11546180.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有