[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个。又由于每次连接最多能产生9个新的长度为\(k\)的子串(即横跨两个字符串之间的子串),因此互不相同的子串个数最多为\(9 \cdot100+100<2^k\),故\(k<10\)

   接下来就只需要记录每个字符串的前缀,后缀以及长度为\(k\)的子串有哪些就好了。

#include<bits/stdc++.h>
using namespace std;
#define N 101
int n,m,a,b;
struct rua
{
    string st,ed;
    set<int>has[10];
    bool check(int k)
      {
      for(int i=0;i<(1<<k);i++)
        if(!has[k].count(i))return false;
      return true;
      }
    int ans()
      {
      for(int k=9;k>0;k--)
        if(check(k))return k;
      return 0;
      }
    rua connect(rua nxt)
      {
      rua res=nxt;
      res.st=st;
      if(st.size()<9)
        res.st=st+nxt.st.substr(0,min(nxt.st.size(),9-st.size()));
      int cpy_len=min(ed.size(),9-nxt.ed.size());
      if(nxt.ed.size()<9)
        res.ed=ed.substr(ed.size()-cpy_len,cpy_len)+nxt.ed;
      for(int k=1;k<=9;k++)
        for(auto i:has[k])res.has[k].insert(i);
      string tmp=ed+nxt.st;
      int len=tmp.size();
      for(int i=0;i<len;i++)
        {
        int value=0;
        for(int d=0;d<9 && i+d<len;d++)
          value=value*2+tmp[i+d]-‘0‘,
          res.has[d+1].insert(value);
        }
      return res;
      }
}f[2*N];
string s;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
      {
      cin>>s;
      int len=s.size();
      for(int j=0;j<len;j++)
        {
        int value=0;
        for(int d=0;d<9 && j+d<len;d++)
          value=value*2+s[j+d]-‘0‘,
          f[i].has[d+1].insert(value);
        }
      int cpy_len=min(9,len);
      f[i].st=s.substr(0,cpy_len);
      f[i].ed=s.substr(len-cpy_len,cpy_len);
      }
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
      {
      scanf("%d%d",&a,&b);
      f[n+i]=f[a].connect(f[b]);
      printf("%d\n",f[n+i].ans());
      }
}

原文地址:https://www.cnblogs.com/DeaphetS/p/9693580.html

时间: 2024-10-09 21:37:05

[Codeforces Round #438][Codeforces 868D. Huge Strings]的相关文章

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 <

Codeforces Round #313 (Div. 2) Equivalent Strings(搜索)

题目大意:判断两个字符串是否等价. 等价的条件(任意一条满足即可):1.两个字符串完全相同 2.把每个字符串分成长度相同的两部分,若a1等价于b1并且a2等价于b2,或者a1等价于b2并且a2等价于b1 由于等价的条件说得很模糊,我卡了不久.等价条件里的第2条的意思是,如果ab两个字符串的两两子串都满足这两个条件,那么ab是等价的(有点绕,对吧),如果我们都已经解读清楚这句话了,显然接下来我们可以递归判断等价了. 首先,如果两个字符串长度不相等,那么肯定不等价:如果当前字符串的长度是奇数,那么我

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 #370 - #379 (Div. 2)

题意: 思路: Codeforces Round #370 A - Memory and Crow 题意:有一个序列,然后对每一个进行ai?=?bi?-?bi?+?1?+?bi?+?2?-?bi?+?3.... 的操作,最后得到了a 序列,给定 a 序列,求原序列. 思路:水. 1 #include <set> 2 #include <map> 3 #include <stack> 4 #include <queue> 5 #include <cstd

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