首页 > 其他分享 >CFR-109解题报告

CFR-109解题报告

时间:2023-03-01 16:00:25浏览次数:54  
标签:字符 109 int REP 解题 ans include CFR dp

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.

标签:字符,109,int,REP,解题,ans,include,CFR,dp
From: https://www.cnblogs.com/cxm1024/p/17168419.html

相关文章

  • CFR-744-Div-3解题报告
    赛时AC2道题,掉大分(哭)A.Casimir'sStringSolitaire题目传送门\(Problem\)给你一个仅含A,B,C的字符串,每次可以删掉一个A和一个B,或一个B和一个C,位置、顺序不......
  • CFR-840-Div-2解题报告
    比赛传送门C.AnotherArrayProblem题意:给你一个数组\(a\),每次可以选两个位置\(i,j(i<j)\),将\([i,j]\)内的所有数替换为\(|a_i-a_j|\)。问最终数组的和最大为多少......
  • CFR-843-Div-2解题报告
    比赛传送门C.InterestingSequence题意:给你\(n,x\),求最小的\(m\gen\),使\(n\&(n+1)\&(n+2)\&\cdots\&m=x\),或判断无解。首先每一位独立,分别考虑。与运算每一位都......
  • CFR-850-Div-1解题报告
    比赛传送门A.Monsters(easyversion)题意:有\(n\)个怪物,每个有\(a_i\)滴血,每次可以选择一个怪物减一滴血,也可以“让所有怪物减一滴血,且如果杀死怪物则重复操作”。......
  • NEERC2002解题报告
    比赛传送门A.AmusingNumbers题意:定义\(n\)以内\(k\)的排名为,数字大小在\(1\simn\)的数字中,字典序小于等于\(k\)的数字个数。给定\(k,m\),求最小的\(n\),使得......
  • NEERC2009解题报告
    B.BusinessCenter有\(m\)个电梯,每个电梯有两个权值\(a,b\),初始在第\(0\)层。你可以选择一个电梯,进行恰好\(n\)次操作,每次要么升高\(a\)要么下降\(b\)。要求......
  • EDU-CFR-115-Div-2解题报告
    赛时AC3道,补题做出来一道A.ComputerGame\(Problem\)有一个\(2\timesn\)的01矩阵,1为障碍,你要从\((1,1)\)走到\((2,n)\),每一步只能向右、上、下、右上、右下走,问......
  • EDU-CFR-116-Div-2解题报告
    比赛传送门做出来五道题。A.ABBalance{%noteinfono-iconproblem%}给你一个只含有a和b的字符串,问怎样通过修改尽可能少的字符,使得ab的数量和ba的数量相......
  • EDU-CFR-138解题报告
    比赛传送门A.CowardlyRooks题意:有一个\(n\timesn\)的棋盘,有\(m\)个位置上有车,保证互不攻击。问是否能将一个车移动一次使得仍然互不攻击。稍加思考可得,如果\(......
  • EDU-CFR-143解题报告
    A.TwoTowers题意:有两个积木塔,由红色/蓝色积木组成,你每次可以将一个塔的塔顶放到另一个塔上,问任意次操作后能否使得两座塔都是红蓝相间。可以将一个塔全部转移到另一......