CFR-109解题报告

A. Hometask

题意:一个字符串,给定 \(k\) 个限制字符对 \((a_i,b_i)\),要求从原串中删除尽可能少的字符,使得不存在一个相邻的限制字符对。保证 \(a_i\ne b_i\),且每个字符最多只出现在一个字符对中。

做法 1

可以设 \(f[i][c]\) 表示前 \(i\) 位,最后一位为 \(c\) 时最少的删除数量,则 \(\forall j,f[i][j]\leftarrow f[i-1][j]+1\),而特殊地 \(f[i][s[i]]\leftarrow\min\limits_{(s[i],j)\text{ is available}}\{f[i-1][j]\}\)。时间复杂度为 \(26n\)

By rng_58

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>

using namespace std;

#define REP(i,n) for((i)=0;(i)<(int)(n);(i)++)
#define foreach(c,itr) for(__typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++)

#define INF (1<<29)

string s,t;
bool bad[30][30];
int dp[100010][30];

int main(void){
    int K,i,j;

    cin >> s;
    cin >> K;
    REP(i,K){
        cin >> t;
        bad[t[0]-'a'][t[1]-'a'] = true;
        bad[t[1]-'a'][t[0]-'a'] = true;
    }

    int N = s.length();
    REP(i,N+1) REP(j,27) dp[i][j] = -INF;
    dp[0][26] = 0;

    REP(i,N) REP(j,27){
        dp[i+1][j] = max(dp[i+1][j],dp[i][j]);
        int x = s[i] - 'a';
        if(!bad[j][x]) dp[i+1][x] = max(dp[i+1][x],dp[i][j]+1);
    }

    int ans = 0;
    REP(i,27) ans = max(ans,dp[N][i]);
    ans = N - ans;
    cout << ans << endl;

    return 0;
}

做法 2

由于每个字符最多只出现在一个字符对中,所以字符对之间没有交集、互不影响。我们可以对每一个字符对单独处理一遍:假设当前字符对为 \((\texttt{a},\texttt{b})\),则对于类似 \(\texttt{aaababbaa}\) 的连续子段,要么只能保留 \(\texttt{a}\),要么只能保留 \(\texttt{b}\),每次贪心地删掉较少的即可。时间复杂度 \(O(kn)\)

By peter50216

#include<stdio.h>
#include<string.h>
char in[101000];
int ot[300];
char tmp[10];
int main(){
    scanf("%s",in);
    int k;
    scanf("%d",&k);
    while(k--){
        scanf("%s",tmp);
        ot[tmp[0]]=tmp[1];
        ot[tmp[1]]=tmp[0];
    }
    int i,j=0;
    int ans=0;
    for(i=0;in[i];i=j){
        if(ot[in[i]]==0){
            j=i+1;
            continue;
        }
        int c1=0,c2=0;
        while(in[j]&&(in[j]==in[i]||in[j]==ot[in[i]])){
            if(in[j]==in[i])c1++;
            else c2++;
            j++;
        }
        if(c1>c2)c1=c2;
        ans+=c1;
    }
    printf("%d\n",ans);
}

B. Colliders

题意:你需要维护一个集合,初始为空。有两种操作:

  1. 尝试加入一个元素。如果集合中没有该元素,且集合中每个元素都与其互质,则成功加入,否则加入失败并输出任意一个不与其互质的元素。
  2. 尝试删除一个元素。如果集合中本来没有该元素则删除失败,否则删除该元素。

可以维护每个质数是否在集合中出现并维护包含该质数的元素。显然每个质数任意时刻只会被一个元素包含,否则会加入失败。每次加入和删除都质因数分解一次即可。

By rng_58

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>

using namespace std;

#define REP(i,n) for((i)=0;(i)<(int)(n);(i)++)
#define foreach(c,itr) for(__typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++)

int minp[100010];
bool activated[100010];
int a[100010];

int check(int x){
    while(x > 1){
        int p = minp[x];
        while(x%p == 0) x /= p;
        if(a[p] != 0) return a[p];
    }
    return -1;
}

void activate(int x){
    int init = x;
    activated[x] = true;
    while(x > 1){
        int p = minp[x];
        while(x%p == 0) x /= p;
        a[p] = init;
    }
}

void deactivate(int x){
    activated[x] = false;
    while(x > 1){
        int p = minp[x];
        while(x%p == 0) x /= p;
        a[p] = 0;
    }
}

void plus_query(int x){ // cout << "+" << x << endl;
    if(activated[x]){
        printf("Already on\n");
        return;
    }

    int ans = check(x);
    if(ans == -1){
        printf("Success\n");
        activate(x);
    } else {
        printf("Conflict with %d\n",ans);
    }
}

void minus_query(int x){ // cout << "-" << x << endl;
    if(!activated[x]){
        printf("Already off\n");
        return;
    }

    printf("Success\n");
    deactivate(x);
}

char buf[10];

int main(void){
    int N,Q,i,j,x;

    scanf("%d%d",&N,&Q);

    for(i=2;i<=N;i++) minp[i] = i;
    for(i=2;i<=N;i++) if(minp[i] == i) for(j=2*i;j<=N;j+=i) minp[j] = min(minp[j],i);

    REP(i,Q){
        scanf("%s",buf);
        scanf("%d",&x);
        if(buf[0] == '+') plus_query(x); else minus_query(x);
    }

    return 0;
}

C.

posted @ 2023-03-01 15:55  曹轩鸣  阅读(23)  评论(0编辑  收藏  举报