• 训练日志 1 (6.14)


    T1 Censoring

      题面如下。

    题目描述
    
    Farmer John has purchased a subscription to Good Hooveskeeping magazine for his cows, so they have plenty of material to read while waiting around in the barn during milking sessions. Unfortunately, the latest issue contains a rather inappropriate article on how to cook the perfect steak, which FJ would rather his cows not see (clearly, the magazine is in need of better editorial oversight).
    FJ has taken all of the text from the magazine to create the string S of length at most 10510^5105​​ characters. He has a list of censored words t1t_1t​1​​ ... tNt_Nt​N​​ that he wishes to delete from S. To do so Farmer John finds the earliest occurrence of a censored word in S (having the earliest start index) and removes that instance of the word from S. He then repeats the process again, deleting the earliest occurrence of a censored word from S, repeating until there are no more occurrences of censored words in S. Note that the deletion of one censored word might create a new occurrence of a censored word that didn't exist before.
    Farmer John notes that the censored words have the property that no censored word appears as a substring of another censored word. In particular this means the censored word with earliest index in S is uniquely defined.Please help FJ determine the final contents of S after censoring is complete.
    FJ把杂志上所有的文章摘抄了下来并把它变成了一个长度不超过10510^5105​​的字符串S。他有一个包含n个单词的列表,列表里的n个单词记为t1t_1t​1​​...tNt_Nt​N​​。他希望从S中删除这些单词。
    FJ每次在S中找到最早出现的列表中的单词(最早出现指该单词的开始位置最小),然后从S中删除这个单词。他重复这个操作直到S中没有列表里的单词为止。注意删除一个单词后可能会导致S中出现另一个列表中的单词
    FJ注意到列表中的单词不会出现一个单词是另一个单词子串的情况,这意味着每个列表中的单词在S中出现的开始位置是互不相同的
    请帮助FJ完成这些操作并输出最后的S
    输入格式
    
    The first line will contain S.
    The second line will contain N, the number of censored words.
    The next N lines contain the strings t1t_1t​1​​ ... tNt_Nt​N​​. Each string will contain lower-case alphabet characters (in the range a..z), and the combined lengths of all these strings will be at most 10510^5105​​.
    第一行包含一个字符串S
    第二行包含一个整数N N<2000 接下来的N行,每行包含一个字符串,第i行的字符串是tit_it​i​​
    输出格式
    
    The string S after all deletions are complete. It is guaranteed that S will not become empty during the deletion process.
    一行,输出操作后的S
    
    样例输入
    
    begintheescapexecutionatthebreakofdawn
    2
    escape
    execution
    
    样例输出
    
    beginthatthebreakofdawn
    Censoring 题面

      一道AC自动机水题,之前做过一道同题目的题,给出的是单个串,用KMP解决,这道题同理AC自动i机。

      通过这道题,对AC自动机才有了初步的认识,要不到现在还不懂KMP。

      不过单纯的AC自动机没法A掉,每次搜串都会浪费掉很多时间。

      所以,用到了Trie图。

      其实。。。怎么说呢。。AC自动机转Trie图只加了两句话

    1 else 
    2 {
    3     if (temp==root) temp->next[i]=root;
    4     else temp->next[i]=temp->fail->next[i];
    5 }
    Trie

      非常的神奇。

      思想差不多就是将AC自动机的fail指针也就是失配边连成实在的边。

      形象的说就是 树->图。

      还有就是 不要用ans记录最终答案 直接用栈一个个弹出即可。

      小弟不才。

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<iostream>
      4 #include<cstring>
      5 using namespace std;
      6 struct Trie{
      7     int count;
      8     Trie *fail,*next[26];
      9     Trie()
     10     {
     11         count=0;
     12         for (int i=0; i<26; ++i) next[i]=NULL;
     13         fail=NULL;
     14     }
     15 }*q[1000003],*pos[1000003];
     16 char str[1000003],a[1000003],ans[1000003];
     17 int stack[1000003];
     18 int n,head,tail,all,t;
     19 Trie *p;
     20 void Insert(Trie *,char []);
     21 void Build(Trie *);
     22 int main()
     23 {
     24 //    freopen("data8.in","r",stdin);
     25 //    freopen("WA.out","w",stdout);
     26     scanf("%s",str+1);
     27     all=strlen(str+1);
     28     scanf("%d",&n);
     29     p=new Trie();
     30     for (int i=1; i<=n; ++i)
     31     {
     32         scanf("%s",a+1);
     33         Insert(p,a);
     34     }
     35     Build(p);
     36     Trie *yy=p;
     37     tail=0;
     38     pos[0]=yy;
     39     for (int i=1; i<=all; ++i)
     40     {
     41         int index=str[i]-'a';
     42         while (yy->next[index]==NULL and yy!=p) {yy=yy->fail;}
     43         yy=yy->next[index];
     44         if (yy==NULL) yy=p;
     45         stack[++tail]=i;
     46         pos[i]=yy;
     47         if (yy->count)
     48         {
     49             tail-=yy->count;
     50             yy=pos[stack[tail]];
     51         }
     52     }
     53     for (int i=1; i<=tail; ++i)
     54         printf("%c",str[stack[i]]);
     55 }
     56 void Build(Trie *root)
     57 {
     58     root->fail=NULL;
     59     q[++tail]=root;
     60     while (tail!=head)
     61     {
     62         Trie *temp=q[++head];
     63         Trie *p=NULL;
     64         for (int i=0; i<26; ++i)
     65         {
     66             if (temp->next[i]!=NULL)
     67             {
     68                 if (temp==root) temp->next[i]->fail=root;
     69                 else
     70                 {
     71                     p=temp->fail;
     72                     while (p!=NULL)
     73                     {
     74                         if (p->next[i]!=NULL)
     75                         {
     76                             temp->next[i]->fail=p->next[i];
     77                             break;
     78                         }
     79                         p=p->fail;
     80                     }
     81                     if (p==NULL) temp->next[i]->fail=root;
     82                 }
     83                 q[++tail]=temp->next[i];
     84             }
     85             else 
     86             {
     87                 if (temp==root) temp->next[i]=root;
     88                 else temp->next[i]=temp->fail->next[i];
     89             }
     90         }
     91     }
     92 }
     93 void Insert(Trie *root,char s[])
     94 {
     95     int len=strlen(s+1);
     96     Trie *temp=root;
     97     for (int i=1; i<=len; ++i)
     98     {
     99         int index=s[i]-'a';
    100         if (temp->next[index]==NULL) temp->next[index]=new Trie();
    101         temp=temp->next[index];
    102     }
    103     temp->count=len;
    104 }
    Censoring AC自动机

    T2 记忆的轮廓

      先%一下出题人和神仙题解https://blog.csdn.net/WerKeyTom_FTD/article/details/53026266

      神仙题。

    题目描述
    
    通往贤者之塔的路上,有许多的危机。
    我们可以把这个地形看做是一颗树,根节点编号为1,目标节点编号为n,其中1-n的简单路径上,编号依次递增,在[1,n]中,一共有n个节点。我们把编号在[1,n]的叫做正确节点,[n+1,m]的叫做错误节点。一个叶子,如果是正确节点则为正确叶子,否则称为错误叶子。莎缇拉要帮助昴到达贤者之塔,因此现在面临着存档位置设定的问题。
    为了让昴成长为英雄,因此一共只有p次存档的机会,其中1和n必须存档。被莎缇拉设置为要存档的节点称为存档位置。当然不能让昴陷入死循环,所以存档只能在正确节点上进行,而且同一个节点不能存多次档。因为通往贤者之塔的路上有影响的瘴气,因此莎缇拉假设昴每次位于树上一个节点时,都会等概率选择一个儿子走下去。每当走到一个错误叶子时,再走一步就会读档。具体的,每次昴到达一个新的存档位置,存档点便会更新为这个位置(假如现在的存档点是i,现在走到了一个存档位置j>i,那么存档点便会更新为j)。读档的意思就是回到当前存档点。初始昴位于1,当昴走到正确节点n时,便结束了路程。莎缇拉想知道,最优情况下,昴结束路程的期望步数是多少?
    输入格式
    
    第一行一个正整数T表示数据组数。
    接下来每组数据,首先读入三个正整数n,m,p。
    接下来m-n行,描述树上所有的非正确边(正确边即连接两个正确节点的边)
    用两个正整数j,k表示j与k之间有一条连边,j和k可以均为错误节点,也可以一个为正确节点另一个为错误节点。
    数据保证j是k的父亲。
    50<=p<=n<=700,m<=1500,T<=5。
    数据保证每个正确节点均有至少2个儿子,至多3个儿子。
    输出格式
    
    T行每行一个实数表示每组数据的答案。请保留四位小数。
    样例
    样例输入
    
    1
    3 7 2
    1 4
    2 5
    3 6
    3 7
    
    样例输出
    
    9.0000
    记忆的轮廓 题面

      概率期望+概率DP+单调队列。

      50%数据

      对于每一个错误节点i,我们可以计算一下它期望再走多少步就会回到存档点,设g[i]为它的期望步数,则g[i]=1+∑(g[j]/d[i]),j为i的错误儿子,d[i]为i的出度。

      用s[i]记录一下每个正确节点i的g[]值和,s[i]=∑(g[j]),j为i的错误儿子。

      然后对于没一个正确节点i,设f[i]为i走到n的期望步数,显然f[n]=0,因此我们可以反推f[1],则

        f[i]=1+f[i+1]/d[i]+1/d[i]*∑(g[j]+f[i]); 化简得f[i]=d[i]+f[i+1]+s[i];   j是i的错误儿子。

      70%数据

      我们设f[i][j],表示在i节点下还剩下j个存档点没设是所需要的最小期望步数。

      设a[i][j]表示从i走到j且其中不设存档点所需要的期望步数,处理时间n2

      关于求a[i][j],有a[i][j]=a[i][j-1]+1+1/d[j-1]*0+1/d[j-1]*sigma{g[k]+a[i][j]},其中k是j-1的错误儿子

      化简得a[i][j]=d[j-1]+a[i][j-1]*d[j-1]+s[j-1]; (划重点,这里需要细致理解)

      得出f[i][j]=min(f[k][j-1]+a[k][i]);

      高能优化

      对于a[i][j],我们可以知道其增长速度是恐怖的,它的大小远远超出我们所需要的答案的大小,因此在转移过程中,我们可以预先计算出答案的上界,发现n/p不会超过14,也就是12位数。

      而且a[i][j]的下界差不多是240,因此我们的i只用从它之后的40步转移而来。

      经过大佬的亲身实验,14就可以AC。。。

      100%数据

      用单调队列优化,具体操作,详见出题人题解。

      小弟不才。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #define LH using namespace std;
     5 LH;
     6 int T,n,m,p,tot,head,tail;
     7 int first[4003],vv[4003],nx[4003];
     8 int du[2003],q[2003];
     9 double f[2003][2003],a[2003][2003],g[2003],s[2003];
    10 inline double min(double a,double b) {return a<b?a:b;}
    11 void Dfs(int );
    12 inline void Clear();
    13 inline void Add(int ,int );
    14 int main()
    15 {
    16     //freopen("6.in","r",stdin);
    17     scanf("%d",&T);
    18     while (T--)
    19     {
    20         tot=0;
    21         Clear();
    22         scanf("%d%d%d",&n,&m,&p);
    23         for (int i=2; i<=n; ++i)
    24             Add(i-1,i),++du[i-1];
    25         for (int i=1; i<=m-n; ++i)
    26         {
    27             int x,y;
    28             scanf("%d%d",&x,&y);
    29             Add(x,y); ++du[x];
    30         }
    31         Dfs(1);
    32         for (int i=1; i<=n; ++i)
    33         {
    34             a[i][i]=0;
    35             for (int j=1; j<=n; ++j)
    36                 if (j!=i)
    37                     a[i][j]=a[i][j-1]*(double)du[j-1]+s[j-1]+(double)du[j-1];
    38         }
    39         for (int i=1; i<=n; ++i)
    40             for (int j=0; j<=p; ++j)
    41                 if (i==n) f[i][j]=0;
    42                 else f[i][j]=(double)1e9+7;
    43         for (int i=n-1; i>=1; --i)
    44             for (int j=1; j<=p-1; ++j)
    45                 for (int k=min(i+40,n); k>i; --k)
    46                 {
    47                     if (i==1 and j==1 and k!=n) break;
    48                     f[i][j]=min(f[k][j-1]+a[i][k],f[i][j]);
    49                 }
    50         printf("%.4lf
    ",f[1][p-1]);
    51     }
    52 }
    53 void Dfs(int k)
    54 {
    55     bool flag=0;
    56     double ooo=0;
    57     for (int i=first[k]; i; i=nx[i])
    58     {
    59         Dfs(vv[i]);
    60         flag=1;
    61         ooo+=g[vv[i]];
    62     }
    63     if (!flag) {g[k]=1;return ;}
    64     if (k>n) {g[k]=1+1/(double)du[k]*ooo; return ;}
    65     if (k<=n) s[k]=ooo;
    66 }
    67 inline void Add(int u,int v)
    68 {
    69     vv[++tot]=v; nx[tot]=first[u]; first[u]=tot;
    70 }
    71 inline void Clear()
    72 {
    73     memset(first,0,sizeof(first));
    74     memset(vv,0,sizeof(vv));
    75     memset(nx,0,sizeof(nx));
    76     memset(du,0,sizeof(du));
    77     memset(a,0,sizeof(a));
    78     memset(g,0,sizeof(g));
    79     memset(s,0,sizeof(s));
    80 }
    记忆的轮廓

    T3 雨天的尾巴

      题面

    题目描述
    
    N个点,形成一个树状结构。有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成所有发放后,每个点存放最多的是哪种物品。
    输入格式
    
    第一行数字N,M
    接下来N-1行,每行两个数字a,b,表示a与b间有一条边
    再接下来M行,每行三个数字x,y,z.如题
    输出格式
    
    输出有N行
    每i行的数字表示第i个点存放最多的物品是哪一种,如果有
    多种物品的数量一样,输出编号最小的。如果某个点没有物品则输出0
    样例
    样例输入
    
    20 50
    8 6
    10 6
    18 6
    20 10
    7 20
    2 18
    19 8
    1 6
    14 20
    16 10
    13 19
    3 14
    17 18
    11 19
    4 11
    15 14
    5 18
    9 10
    12 15
    11 14 87
    12 1 87
    14 3 84
    17 2 36
    6 5 93
    17 6 87
    10 14 93
    5 16 78
    6 15 93
    15 5 16
    11 8 50
    17 19 50
    5 4 87
    15 20 78
    1 17 50
    20 13 87
    7 15 22
    16 11 94
    19 8 87
    18 3 93
    13 13 87
    2 1 87
    2 6 22
    5 20 84
    10 12 93
    18 12 87
    16 10 93
    8 17 93
    14 7 36
    7 4 22
    5 9 87
    13 10 16
    20 11 50
    9 16 84
    10 17 16
    19 6 87
    12 2 36
    20 9 94
    9 2 84
    14 1 94
    5 5 94
    8 17 16
    12 8 36
    20 17 78
    12 18 50
    16 8 94
    2 19 36
    10 18 36
    14 19 50
    4 12 50
    
    样例输出
    
    87
    36
    84
    22
    87
    87
    22
    50
    84
    87
    50
    36
    87
    93
    36
    94
    16
    87
    50
    50
    
    数据范围与提示
    
    1<=N,M<=100000
    1<=a,b,x,y<=N
    1<=z<=10910^9109​​
    雨天的尾巴 题面

      权值线段树+线段树合并+LCA+树上差分

      这道题其实思想不是很难,一道单纯的数据结构题。

      一开始想的是LCA+树上差分,本着能那多少分是多少的原则,暴力了15。

      其实当时的脑子烧了,没想到离散化。。。(加后50)

      挂一下错误

      1.LCA打错,问题在初始化上,计算fa[i][j]时要在i入队是处理,因为当它入队,说明它的父亲节点的所有fa已经全部处理完

      2.注意l r 和lc rc 的区别,前者表示区间,后者表示子节点

      3.最大的问题在于对Merge的处理,调了很长时间(其实就是懒得手模样例),注意究竟是在lc rc之间转移还是在x y之间转移,这很重要,不过画图理解之后感觉清楚很多

      (可能我的代码很奇怪,与众大佬不相符,望海涵)

      小弟不才。

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 #define Meng using namespace std;
      7 Meng;
      8 struct node{
      9     int lc,rc;
     10     int max,num;
     11 }tr[10000003];
     12 int n,m,tot,hzoi,hzoj,cnt;
     13 int first[200003],vv[200003],nx[200003];
     14 int dep[200003],f[200003][20];
     15 int v[200003],q[200003],head,tail;
     16 int ll[200003],rr[200003],a[200003],b[200003],c[200003];
     17 int ans[200003];
     18 void Build(int );
     19 void Dfs(int );
     20 int Find(int ,int );
     21 int Merge(int ,int );
     22 void Insert(int ,int ,int &,int ,int );
     23 inline void Up(int );
     24 inline void Add(int ,int );
     25 int main()
     26 {
     27 //    freopen("1.txt","r",stdin);
     28 //    freopen("11.txt","w",stdout);
     29     scanf("%d%d",&n,&m);
     30     for (int i=1; i<n; ++i)
     31     {
     32         int x,y;
     33         scanf("%d%d",&x,&y);
     34         Add(x,y); Add(y,x);
     35     }
     36     hzoj=n; hzoi=0;
     37     while (hzoj) hzoj>>=1,hzoi++; 
     38     head=1; tail=0;
     39     Build(1);
     40     for (int i=1; i<=m; ++i)
     41     {
     42         scanf("%d%d%d",&ll[i],&rr[i],&a[i]);
     43         b[i]=a[i];
     44     }
     45     sort(b+1,b+m+1);
     46     cnt=unique(b+1,b+m+1)-b-1;
     47     for (int i=1; i<=m; ++i)
     48     {
     49         int ooo=a[i];
     50         a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
     51         c[a[i]]=ooo;
     52     }
     53     cnt=n;
     54     for (int i=1; i<=m; ++i)
     55     {
     56         int lca=Find(ll[i],rr[i]);
     57         Insert(1,m,ll[i],a[i],1);
     58         Insert(1,m,rr[i],a[i],1);
     59         Insert(1,m,lca,a[i],-1);
     60         if (f[lca][0]) Insert(1,m,f[lca][0],a[i],-1);
     61     }
     62     memset(v,0,sizeof(v));
     63     Dfs(1);
     64     for (int i=1; i<=n; ++i)
     65         printf("%d
    ",ans[i]);
     66     return 0;
     67 }
     68 void Dfs(int k)
     69 {
     70     v[k]=1;
     71     for (int i=first[k]; i; i=nx[i])
     72     {
     73         if (v[vv[i]]) continue;
     74         Dfs(vv[i]);
     75         Merge(k,vv[i]);
     76     }
     77     if (tr[k].num>0) ans[k]=c[tr[k].max];
     78     return ;
     79 }
     80 int Merge(int x,int y)
     81 {
     82     if (x==0 or y==0) return x+y;
     83     tr[x].lc=Merge(tr[x].lc,tr[y].lc);
     84     tr[x].rc=Merge(tr[x].rc,tr[y].rc);
     85     if (tr[x].lc==0 and tr[x].rc==0)
     86     {
     87         if (tr[x].max!=tr[y].max)
     88         {
     89             if (tr[tr[x].lc].num<tr[y].num)
     90                 tr[x].max=tr[y].max,tr[x].num=tr[y].num;
     91         }
     92         else tr[x].num=tr[x].num+tr[y].num;
     93     }
     94     else Up(x);
     95     return x;
     96 }
     97 void Insert(int L,int R,int &k,int val,int w)
     98 {
     99     if (!k) k=++cnt;
    100     if (L==R) {tr[k].num+=w; tr[k].max=val; return ;}
    101     int M=(L+R)>>1;
    102     if (val<=M) Insert(L,M,tr[k].lc,val,w);
    103     else Insert(M+1,R,tr[k].rc,val,w);
    104     Up(k);
    105     return ;
    106 }
    107 inline void Up(int k)
    108 {
    109     if (tr[tr[k].lc].num==0) tr[k].max=tr[tr[k].rc].max,tr[k].num=tr[tr[k].rc].num;
    110         else if (tr[tr[k].rc].num==0) tr[k].max=tr[tr[k].lc].max,tr[k].num=tr[tr[k].lc].num;
    111         else
    112         {
    113                 if (tr[tr[k].lc].num>=tr[tr[k].rc].num)
    114                         tr[k].max=tr[tr[k].lc].max,tr[k].num=tr[tr[k].lc].num;
    115                 else tr[k].max=tr[tr[k].rc].max,tr[k].num=tr[tr[k].rc].num;
    116         }
    117 }
    118 int Find(int x,int y)
    119 {
    120     if (dep[x]<dep[y]) swap(x,y);
    121     for (int i=hzoi; i>=0; --i)
    122         if (dep[f[x][i]]>=dep[y]) x=f[x][i];
    123     if (x==y) return x;
    124     for (int i=hzoi; i>=0; --i)
    125         if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    126     return f[x][0];
    127 }
    128 void Build(int k)
    129 {
    130     dep[k]=1;
    131     q[++tail]=k;
    132     v[k]=1;
    133     while (head<=tail)
    134     {
    135         int nan=q[head++];
    136         for (int i=first[nan]; i; i=nx[i])
    137         {
    138             int ruo=vv[i];
    139             if (v[ruo]) continue;
    140             dep[ruo]=dep[nan]+1;
    141             f[ruo][0]=nan;
    142             q[++tail]=ruo;
    143             v[ruo]=1;
    144             for (int j=1; j<=hzoi; ++j)
    145             {
    146                 if (f[ruo][j-1]==0) break;
    147                 f[ruo][j]=f[f[ruo][j-1]][j-1];
    148             }
    149         }
    150     }
    151 }
    152 inline void Add(int u,int v)
    153 {
    154     vv[++tot]=v; nx[tot]=first[u]; first[u]=tot;
    155 }
    雨天的尾巴

      

      小结:这次的考试得到的教训很多,有心态的,有知识的,总之还是要在接下来的训练中努力提升自己,永不放弃。(详见6.14训练反思)

  • 相关阅读:
    elasticDump的安装使用
    centos7中给Elasticsearch5 安装bigdesk
    centos7下Elasticsearch5.2.2和head 插件环境搭建
    渗透测试入门DVWA 环境搭建
    windows环境下运行Elasticsearch
    UltraISO刻录CentOS 7安装指南
    TCP 协议中的 Window Size与吞吐量
    php 抛出异常
    php获取字符串长度
    php批量转换时间戳
  • 原文地址:https://www.cnblogs.com/LH-Xuanluo/p/11083786.html
Copyright © 2020-2023  润新知