D. Huge Strings Codeforces Round #438 by Sberbank and Barcelona Bootcamp (Div. 1 + Div. 2 combined)

http://codeforces.com/contest/868/problem/D

优化:两个串合并

原有状态+ 第一个串的尾部&第二个串的头部的状态

串变为第一个串的头部&第二个串的尾部

注意:

头尾不能重复

如串A合并串A

这就意味着串的头尾不能有重合,

详见代码

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <time.h>
#include <string>
#include <set>
#include <map>
#include <list>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
#include <ext/rope>
#include <algorithm>
#include <iostream>
using namespace std;
#define ll long long
#define minv 1e-6
#define inf 1e9
#define pi 3.1415926536
#define E  2.7182818284
const ll mod=1e9+7;//998244353
const int maxn=201;

int w=15;

int f[maxn][1<<(15+1)]={0},add[15+2];
int len,value;
string str,s,pre[maxn],post[maxn];

void work(int index,string a)
{
    int i,j,z;
    len=a.length();
    for (j=1;j<=w;j++)
    {
        value=0;
        z=(1<<(j-1))-1;
        for (i=0;i<len;i++)
        {
            value=(value<<1|(a[i]==‘1‘));
            if (i>=j-1)
            {
                f[index][value+add[j]]=1;
                value=value&z;
            }
        }
    }
}

int main()
{
    int n,q,Q,x,y,i;
    add[1]=0;
    for (i=2;i<=w+1;i++)
        add[i]=(1<<i)-2;

    scanf("%d",&n);
    for (i=1;i<=n;i++)
    {
        cin>>str;
        work(i,str);
        len=str.size();
        if (len<=w)
            pre[i]=str;
        else
        {
            pre[i]=str.substr(0,w);
            if (len>=w+w)
                post[i]=str.substr(str.length()-w,w);
            else
                post[i]=str.substr(str.length()-len+w,len-w);
        }
    }

    scanf("%d",&q);
    for (Q=n+1;Q<=n+q;Q++)
    {
        scanf("%d%d",&x,&y);

        for (i=0;i<add[w+1];i++)
            f[Q][i]=f[x][i] | f[y][i];

        if (post[x].empty())
            str=pre[x];
        else if (post[x].length()<w)
            str=pre[x].substr(pre[x].length()-(w-post[x].length()),w-post[x].length())+post[x];
        else
            str=post[x];
        str+=pre[y];

        work(Q,str);

        str=pre[x]+post[x]+pre[y]+post[y];
        pre[Q]=str.substr(0,min(w,(int)str.length()));
        str.erase(0,min(w,(int)str.length()));
        post[Q]=str.substr(str.length()-min(w,(int)str.length()),min(w,(int)str.length()));

        for (i=0;i<add[w+1];i++)
            if (f[Q][i]==0)
                break;
        printf("%d\n",(int)(log(2+i+minv)/log(2))-1);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/cmyg/p/9520984.html

时间: 2024-08-03 04:14:32

D. Huge Strings Codeforces Round #438 by Sberbank and Barcelona Bootcamp (Div. 1 + Div. 2 combined)的相关文章

Codeforces Round #438 by Sberbank and Barcelona Bootcamp (Div. 1 + Div. 2 combined) F. Yet Another Minimization Problem

$f[i][k]$ 表示前 $i$ 个分成 $k$ 段,且最后一段以 $i$ 结尾的最小值 容易写出转移方程 $f[i][k] = \min \{f[j][k - 1] + calc(j+1,i)\}$ 因为具有决策单调性(打表 or 证明(不会)),就可以一种分治算法来优化 具体实现就是 $solve(l,r,L,R)$ 表示要求出 $(l,r)$ 之间的 dp 值,而决策点能取的区间为 $[L,R]$ 先暴力求出 $mid=\dfrac{l+r}{2}$ 的决策点 $pos$,再调用 $so

[Codeforces Round #438][Codeforces 868D. Huge Strings]

题目链接:868D - Huge Strings 题目大意:有\(n\)个字符串,\(m\)次操作,每次操作把两个字符串拼在一起,并询问这个新串的价值.定义一个新串的价值\(k\)为:最大的\(k\),使得这个新串包含所有长度为\(k\)的01串(这样的字符串有\(2^k\)个) 题解:首先来证明对于任何的串,这个\(k\)的值不会超过9 若\(k=10\),由所有字符串的长度总和不超过100,因此在初始的\(n\)个串里,互不相同的长度为\(k\)的子串不超过100个.又由于每次连接最多能产生

Codeforces Round #129 (Div. 1)E. Little Elephant and Strings

Codeforces Round #129 (Div. 1)E. Little Elephant and Strings 题意:给出n个字符串,问每个字符串有多少个子串(不同位置,相同的子串视作不同)至少出现在这n个字符串中的k个当中. 解法:这题学到了一个SAM的新技能,对于这多个串,建SAM的时候,不是把它们连在一起,建立SAM,而是先给它们建立Trie树,然后广搜这棵Trie树,对于Trie树上的V节点,在建SAM的时候,它应该接在Trie树上他的父亲节点后面,我们用TtoM[U]表示Tr

水题 Codeforces Round #302 (Div. 2) A Set of Strings

题目传送门 1 /* 2 题意:一个字符串分割成k段,每段开头字母不相同 3 水题:记录每个字母出现的次数,每一次分割把首字母的次数降为0,最后一段直接全部输出 4 */ 5 #include <cstdio> 6 #include <iostream> 7 #include <cstring> 8 #include <string> 9 #include <algorithm> 10 using namespace std; 11 12 con

Codeforces Round #112 (Div. 2) C Another Problem on Strings

题目链接:Codeforces Round #112 (Div. 2) C Another Problem on Strings 题意:给出一个只含0,1的序列,求序列中和为n的子序列有多少个. 思路:预处理出序列的前缀和,然后枚举序列时,记录(vis)该位置之前已有的前缀和,再查询(sum[i]-n)的个数,即以该位置为结束的子序列和为n的个数. 注意:vis数组中0应该始终存在,初始化vis[0]=1(why?,因为sum[i]本身就等于n算一个方法数). 举一反三:类似的就已经可以得到,任

Codeforces Round #302 (Div. 2) A B C

Codeforces Round #302 (Div. 2) A. Set of Strings 字符串 q 被称为 "beautiful" 当且仅当 q 可以被拆分成 k 个子串 (s1, s2, s3, ... , sk) 并且任意两个字串满足首字母不一样. 直接模拟,对 q 的每个字符进行判断,如果该字符在之前没有出现过,那么从它开始就可以组成一个新的字符串,并且计数,如果到了k 了则把之后的都归为一个字符串. #include <cstring> #include

Codeforces Round #FF(255) DIV2 C - DZY Loves Sequences

A - DZY Loves Hash 水题,开辟一个数组即可 #include <iostream> #include <vector> #include <algorithm> #include <string> using namespace std; int main(){ int p,n; cin >> p >> n; vector<bool> buckets(302,false); bool flag = fal

Codeforces Round #FF (Div. 2) 题解

比赛链接:http://codeforces.com/contest/447 A. DZY Loves Hash time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output DZY has a hash table with p buckets, numbered from 0 to p?-?1. He wants to insert n 

Codeforces Round #256 (Div. 2/B)/Codeforces448B_Suffix Structures(字符串处理)

解题报告 四种情况相应以下四组数据. 给两字符串,推断第一个字符串是怎么变到第二个字符串. automaton 去掉随意字符后成功转换 array 改变随意两字符后成功转换 再者是两个都有和两个都没有 #include <iostream> #include <cstdio> #include <cstring> #include <stdlib.h> #include <algorithm> #include <cmath> usi