A. Binary Protocol

水题,模拟统计出连续的0隔开的每段1的个数即可。

#include <bits/stdc++.h>
using namespace std;
char s[110];
int n;
int main()
{
    while(~scanf("%d", &n)){
        scanf("%s", s);
        int len = strlen(s);
        int t = 0;
        s[len] = '0';
        for(int i=0; i<=len; i++){
            if(s[i] == '0'){
                printf("%d", t);
                t = 0;
            }
            else{
                t++;
            }
        }
        printf("\n");
    }
}

B. Five-In-a-Row

把每个.位置用’X’替换之后去check即可,注意替换之后要换回来。

#include <bits/stdc++.h>
using namespace std;
char maze[12][12];
bool check(int x, int y){
    maze[x][y]='X';
    for(int i=0; i<10; i++){
        for(int j=0; j<10; j++){
            if(maze[i][j]=='O'||maze[i][j]=='.') continue;
            int t1 = 0, t2 = 0, t3 = 0, t4 = 0;
            for(int k=j; k<10; k++){
                if(maze[i][k] == 'X') t1++;
                else break;
            }
            for(int k=i; k<10; k++){
                if(maze[k][j] == 'X') t2++;
                else break;
            }
            for(int k=0; i+k<10&&j+k<10; k++){
                if(maze[i+k][j+k]=='X') t3++;
                else break;
            }
            for(int k=0; i-k>=0&&j+k<10; k++){
                if(maze[i-k][j+k]=='X') t4++;
                else break;
            }
            if(t1>=5||t2>=5||t3>=5||t4>=5){
                maze[x][y] = '.';
                return 1;
            }
        }
    }
    maze[x][y] = '.';
    return 0;
}
int main()
{
    for(int i=0; i<10; i++){
        scanf("%s", maze[i]);
    }
    for(int i=0; i<10; i++){
        for(int j=0; j<10; j++){
            if(maze[i][j]=='.'){
                if(check(i,j)){
                    puts("YES");
                    return 0;
                }
            }
        }
    }
    puts("NO");
    return 0;
}

C. Multi-judge Solving

题意:在codeforces上有n个不同难度的题目需要你去解决,现在你在其他OJ上已经解决的最大难度的题目为k,你要解决一个难度为s的问题的前提条件是你当前解决的所有问题的最大难度d要大于等于s,现在cf上这些题目你需要全部去解决,现在问你要通过其他OJ解决几道问题才行

解法:当前的a[i]个问题中,如果这个问题难度a[i]*2小于k,那么k = max(k,a[i]),因为我们可以解决这个问题并且更新k值,否则的话我们就一直递增这个k去找a[i],这时候ans加加

#include <bits/stdc++.h>
using namespace std;
int n, k, mx, a[1010];

int main()
{
    while(~scanf("%d %d", &n,&k)){
        for(int i=1; i<=n; i++) scanf("%d", &a[i]);
        sort(a+1, a+n+1);
        mx = k;
        int ans = 0;
        for(int i=1; i<=n; i++){
            if(mx>=(a[i]+1)/2){
                mx = max(mx, a[i]);
            }
            else{
                while(2*mx < a[i]){
                    ans++;
                    mx*=2;
                }
                mx = max(mx, a[i]);
            }
        }
        printf("%d\n", ans);
    }
}

D. Suitable Replacement

题意:给了一个带有?的原串,又给了一个文本串,问把这些问号怎么替换可以使得文本串在原串的出现次数最多?

解法:贪心,把所有的?存下来,然后一个个的去补全一个完整的文本串肯定是最优的,还要注意处理最后剩下的一段。

#include <bits/stdc++.h>
using namespace std;
char s[1000010], t[1000010];
int cnt[30];
vector <int> v;
int main()
{
    scanf("%s", s);
    scanf("%s", t);
    for(int i=0; s[i]; i++){
        if(s[i] == '?') v.push_back(i);
        else cnt[s[i]-'a']++;
    }
    int l = 0, st = 0, sz = v.size(), len = strlen(t);
    while(1){
        if(!cnt[t[st]-'a']){
            if(l<sz){
                s[v[l]] = t[st];
                l++;
            }
            else{
                break;
            }
        }
        else{
            cnt[t[st]-'a']--;
        }
        st++;
        if(st == len) st = 0;
    }
    for(int i=l; i<sz; i++) s[v[i]] = 'a';
    printf("%s\n", s);
    return 0;
}

E. Minimal Labels

题意:1.对于原来编号u,v的两点,若存在一条从u指向v的边,那么重新编号后,u的编号要小于v的编号。2.重新编号后,新的编号恰好构成一个1~N的排列。从1到N,依次输出该节点的新编号。如果有多种编号方案,输出字典序最小的方案。

解法:1.题目中给出边< x,y >,那么存边时存< y,x >,并记录入度。2.执行Topsort标准操作,压入大根堆中而不是栈中。 此时从N到1,依次给取出的堆顶元素进行编号。当然还有一种对应的小根堆的做法,为什么这种做法错了呢?
举个栗子:3 1 3 1 小根堆输出的是3 1 2而正确答案是2 3 1,官方题解也给出了证明。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e6+7;
int n, m, lable[maxn], du[maxn];
vector <int> G[maxn];
priority_queue <int> q;

int main()
{
    while(~scanf("%d%d", &n,&m)){
        for(int i=1; i<=m; i++){
            int u, v;
            scanf("%d %d", &u,&v);
            G[v].push_back(u);
            du[u]++;
        }
        for(int i=1; i<=n; i++) if(du[i]==0) q.push(i);
        int ans = n;
        while(!q.empty()){
            int x = q.top(); q.pop();
            lable[x] = ans--;
            for(auto i : G[x]){
                du[i]--;
                if(du[i] == 0){
                    q.push(i);
                }
            }
        }
        for(int i=1; i<=n; i++){
            printf("%d ", lable[i]);
        }
        printf("\n");
    }
    return 0;
}

F. String Compression
题意:给了一个字符串,然后我们可以执行折叠操作,比如aaaa可以变成4a,其中前面的数字用10进制表示,然后要问这个字符串可能变成的字符串的最短长度。

解法:KMP+DP。首先要懂一个东西,就是如何利用KMP的nxt数组求出字符串的周期。(周期就是len-nxt[len]),证明在白书上有,非常简单,不再赘述。这里讲讲这道题的做法,DP[i]表示到i字符能够择出的最短长度。那么可以转移到什么地方呢?我们通过枚举的方式,计算枚举的串是否为周期串进行转移即可。看代码吧,写的非常清楚。

复杂度O(n*n)

#include <bits/stdc++.h>
using namespace std;
const int maxn = 8005;
int n,fail[maxn][maxn], num[maxn], dp[maxn];
char s[maxn];
void Getmin(int &x, int y){
    if(y<x) x=y;
}
void getFail(){
    for(int st=0; st<n; st++){
        int len=n-st, j=-1;
        fail[st][0]=-1;
        for(int i=1; i<len; i++){
            while(j>=0&&s[st+j+1]!=s[st+i]) j=fail[st][j];
            if(s[st+j+1]==s[st+i]) j++;
            fail[st][i]=j;
        }
    }
}
int main()
{
    scanf("%s", s);
    n = strlen(s);
    for(int i=1; i<=n; i++) num[i]=num[i/10]+1;
    memset(dp, 0x3f, sizeof(dp));
    getFail();
    //dp[0]=0;
    for(int st=0; st<n; st++){
        for(int len=1; st+len<=n; len++){
            Getmin(dp[st+len-1],dp[st-1]+len+1);
            int loop=len-1-fail[st][len-1];
            if(len%loop==0){
                Getmin(dp[st+len-1], dp[st-1]+loop+num[len/loop]);
            }
        }
    }
    printf("%d\n", dp[n-1]);
    return 0;
}

G. Tree Queries

题意:给出一颗树,两种操作一种是把某一个点涂成黑色,另外一个是计算这个点到所有黑点的路径上的最小的点的标号。

解法:参见官方题解。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000010;
int n, q, last, x, minn, f[maxn];
vector <int> G[maxn];
void dfs(int x, int val){
    f[x] = val;
    for(auto v : G[x]){
        if(!f[v]) dfs(v, min(val, v));
    }
}
int main()
{
    while(~scanf("%d %d", &n,&q))
    {
        for(int i=0; i<maxn; i++) G[i].clear();
        for(int i=1; i<n; i++){
            int u,v;
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        int op;
        scanf("%d %d", &op,&x);
        last = 0;
        x = (x+last)%n+1;
        minn = x;
        dfs(x, x);
        q--;
        while(q--){
            scanf("%d %d", &op,&x);
            x = (x+last)%n+1;
            if(op == 1){
                minn = min(minn, f[x]);
            }
            else{
                last = min(minn, f[x]);
                printf("%d\n", last);
            }
        }
    }
}
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000010;
int n, q, last, x, minn, f[maxn];
vector <int> G[maxn];
void dfs(int x, int val){
    f[x] = val;
    for(auto v : G[x]){
        if(!f[v]) dfs(v, min(val, v));
    }
}
int main()
{
    while(~scanf("%d %d", &n,&q))
    {
        for(int i=0; i<maxn; i++) G[i].clear();
        for(int i=1; i<n; i++){
            int u,v;
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        int op;
        scanf("%d %d", &op,&x);
        last = 0;
        x = (x+last)%n+1;
        minn = x;
        dfs(x, x);
        q--;
        while(q--){
            scanf("%d %d", &op,&x);
            x = (x+last)%n+1;
            if(op == 1){
                minn = min(minn, f[x]);
            }
            else{
                last = min(minn, f[x]);
                printf("%d\n", last);
            }
        }
    }
}