CF - 1117 F Crisp String

题目传送门

题解:

枚举非法对。

  如果 ‘a‘  和 ’b‘ 不能相邻的话,那么删除 ‘a‘ ‘b‘之间的字符就是非法操作了。 假设题目给定的字符串为 "acdbe",所以删除cd是非法操作, 因为cd是非法了,所以cde也是非法操作,

    也就是说找到所有的非法操作之后往外推,比他多删的状态就一样是非法的了,当然对于上述的“acdbe"来说,不能确定 ”acd"是非法操作,因为在枚举非法对的时候,该非法对的字符并不能被删除。

然后把所有非法对的非法状态都存下来。然后从没删除的状态往外搜,就好了。

代码:

/*
code by: zstu wxk
time: 2019/03/06
Problem Link: http://codeforces.com/contest/1117/problem/F
Solve:
*/
#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const int _inf = 0xc0c0c0c0;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL _INF = 0xc0c0c0c0c0c0c0c0;
const LL mod =  (int)1e9+7;
const int N = 1e5 + 100;
char s[N];
int a[20][20], cnt[20];
int tmp[1<<18], gg[1<<18];
int n, m, k;
void solve(int u, int v){
    memset(tmp, 0, sizeof(tmp));
    for(int i = 1, j; i <= n;){
        while(i <= n && s[i]-‘a‘ != u) ++i;
        int t = 0;
        j = i+1;
        while(j <= n && s[j] -‘a‘ != u && s[j]-‘a‘ !=  v) {
            t |= 1 << s[j]-‘a‘;
            ++j;
        }
        if(j > n) break;
        if(s[j] - ‘a‘ == v){
            i = j+1;
            tmp[t] = 1;
        }
        if(s[j] - ‘a‘ == u)
            i = j;
    }
    for(int i = 0; i <= k; ++i){
        if(tmp[i]){
            gg[i] = 1;
            for(int j = 0; j < m; ++j){
                if(j == u || j == v) continue;
                tmp[i|(1<<j)] = 1;
            }
        }
    }
    return ;
}
int vis[1<<18];
int ans;
void DFS(int x, int len){
    if(vis[x]) return ;
    vis[x] = 1;
    ans = min(ans, len);
    for(int i = 0; i < m; ++i){
        if(gg[x | (1<<i)]) continue;
        DFS(x|1<<i, len-cnt[i]);
    }
    return ;
}

void Ac(){
    memset(gg, 0, sizeof(gg));
    memset(cnt, 0, sizeof cnt);
    scanf("%s", s+1);
    for(int i = 0; i < m; ++i)
        for(int j = 0; j < m; ++j)
            scanf("%d", &a[i][j]);
    k = (1<<m) - 1;
    for(int i = 0; i < m; ++i)
        for(int j = 0; j < m; ++j)
            if(a[i][j] == 0)
                solve(i,j);
    for(int i = 1; i <= n; ++i){
        cnt[s[i]-‘a‘]++;
    }
    ans = n;
    DFS(0, n);
    printf("%d\n", ans);
    return ;
}
int main(){
    while(~scanf("%d%d", &n, &m)){
        Ac();
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/MingSD/p/10496334.html

时间: 2024-11-09 10:32:13

CF - 1117 F Crisp String的相关文章

CF 1117 E. Decypher the String

E. Decypher the String 链接 题意: 有一个字符串,一些操作,每次操作交换两个位置的字符,经过这些操作后,会得到新的字符串.给你新的字符串,求原来的串.可以有3次询问,每次询问给出一个字符串,返回操作后的字符串. 分析: 如果长度小于等于26,那么询问abc...xyz,就可以知道每个位置操作后的对应的位置.那么长度大于26的时候,考虑均分成26段,每段是一个字符,然后可以知道每段对应的位置集合.继续在每一段内均分即可,均分3次,即可到单个位置. 代码实现很有意思,写成一个

CF 494 F. Abbreviation(动态规划)

题目链接:[http://codeforces.com/contest/1003/problem/F] 题意:给出一个n字符串,这些字符串按顺序组成一个文本,字符串之间用空格隔开,文本的大小是字母+空格的个数.在这个文本中找k(k>=2)个区间,使得这k个区间完全相同,字符串不能分开,然后把每段的字符串变成单个的字符,并去掉中间的空格.可能有多种方案,求文本的最小长度.[表达能力有限,望理解,具体可以看题目] You are given a text consisting of nn space

Crisp String CodeForces - 1117F (状压)

#include <iostream> #include <algorithm> #include <cstdio> #include <math.h> #include <set> #include <map> #include <queue> #include <string> #include <string.h> #define REP(i,a,n) for(int i=a;i<=n;

CF 474/F, 线段树 + 一点数学

啊回家真是颓,一周了什么都没做 题目大意:给出一坨数,每次询问区间当中有多少个数能把其他区间内的所有数整除 解:由于我是知道这个是线段树专题,所以一开始就奔着gcd去了,想了一下还真是gcd,因为如果一个数a能整除另一个数b,那么gcd(a,b)一定为a,所以这说明可以做区间加法,直接上线段树就是,询问个数的时候还傻叉地想了一会,后面发现给每个线段记一下当前线段表示的gcd有几个就行,合并直接合并(可以证明现在这个线段的gcd一定是作为最优的取值,因为没有数等于这个gcd说明没有数能整除当前区间

【Cf #502 F】The Neutral Zone

本题把$log$化简之后求得就是每个质数$f$前的系数,求系数并不难,难点在于求出所有的质数. 由于空间限制相当苛刻,$3e8$的$bitset$的内存超限,我们考虑所有的除了$2$和$3$以外的质数,他们可以被表示成$p \equiv \pm 1 (mod \; 6) $.(具体来讲就是把数表示成$6k, 6k+1, 6k+2, 6k+3, 6k+4, 6k+5$,显然只有余数为$1$或$5$才有成为质数的可能性).然后我们需要筛的个数就变成原来的三分之一了. 另一个做法:分块,一部分一部分筛

树的直径| CF#615Div3 F. Three Paths on a Tree

F. Three Paths on a Tree 思路 两种方法: 1.两次bfs求树的直径,顺便求出一个直径端点到所有点的最短距离:再bfs一次,求另一个直径上的端点到其它所有点的最短距离:之后枚举第三个端点(不等于端点1和端点2),dis(a,b) + dis(b,c) + dis(a,c) 再除以 2 就是最终答案,因为每个路径走了两次所以除以2. 2.dfs求树的直径,记录直径上的所有点.从直径上的所有点去搜索它们到不在直径上的点的最远距离.最后直径+这个最远距离就是答案 代码1 bfs

CF 977 F. Consecutive Subsequence

题意: 第一场div3, 求的是一个序列中最长连续(a,a+1,a+2...)子序列. 分析: 设一个DP[i] 表示 序列以i结尾的最长长度, 一开始都设为0. 那么如果这个数是a, 他的最长长度就是 Dp[a-1] + 1, 最后找出最大那个值就是答案, 倒回去输出序列就可以了 #include <bits/stdc++.h> using namespace std; const int maxN = 2e5 + 7; int a[maxN]; map<int, int> dp

cf Round 613

A.Peter and Snow Blower(计算几何) 给定一个点和一个多边形,求出这个多边形绕这个点旋转一圈后形成的面积.保证这个点不在多边形内. 画个图能明白 这个图形是一个圆环,那么就是这个点距离多边形边缘最远的距离形成的圆面积减去这个点距离多边形边缘最近的距离形成的圆面积.我们可以得出距离最远的点一定是多边形的顶点.而距离最近的点不一定是多边形的顶点,但是在多边形的边上.我们用勾股定理判断点与每条边形成的三角形的两边角.如果有一个边角是钝角,则表示距离最近的点是顶点.如果都是锐角,则

Rearrange a string so that all same characters become d distance away

http://www.geeksforgeeks.org/rearrange-a-string-so-that-all-same-characters-become-at-least-d-distance-away/ Given a string and a positive integer d. Some characters may be repeated in the given string. Rearrange characters of the given string such t