6/14考试总结

实锤:我就是一个超级大垃圾!!!

必须从这个视角俯瞰自己了啊

T1:Censoring

FJ把杂志上所有的文章摘抄了下来并把它变成了一个长度不超过1e5的字符串S。他有一个包含n个单词的列表,列表里的n个单词记为ti,他希望从S中删除这些单词。
FJ每次在S中找到最早出现的列表中的单词(最早出现指该单词的开始位置最小),然后从S中删除这个单词。他重复这个操作直到S中没有列表里的单词为止。注意删除一个单词后可能会导致S中出现另一个列表中的单词
FJ注意到列表中的单词不会出现一个单词是另一个单词子串的情况,这意味着每个列表中的单词在S中出现的开始位置是互不相同的
请帮助FJ完成这些操作并输出最后的S。第一行包含一个字符串S
第二行包含一个整数N N<2000 接下来的N行,每行包含一个字符串i​​1​​...tNt_NtN​​。他希望从S中删除这些单词。
FJ每次在S中找到最早出现的列表中的单词(最早出现指该单词的开始位置最小),然后从S中删除这个单词。他重复这个操作直到S中没有列表里的单词为止。注意删除一个单词后可能会导致S中出现另一个列表中的单词
FJ注意到列表中的单词不会出现一个单词是另一个单词子串的情况,这意味着每个列表中的单词在S中出现的开始位置是互不相同的
请帮助FJ完成这些操作并输出最后的S
5​​的字符串S。他有一个包含n个单词的列表,列表里的n个单词记为t1t_1t1​​...tNt_NtN​​。他希望从S中删除这些单词。
FJ每次在S中找到最早出现的列表中的单词(最早出现指该单词的开始位置最小),然后从S中删除这个单词。他重复这个操作直到S中没有列表里的单词为止。注意删除一个单词后可能会导致S中出现另一个列表中的单词
FJ注意到列表中的单词不会出现一个单词是另一个单词子串的情况,这意味着每个列表中的单词在S中出现的开始位置是互不相同的
请帮助FJ完成这些操作并输出最后的S

一本通水题,AC自动机+栈,hash也能过,过多的回溯fail指针导致T,40。

AC自动机尝试匹配时需要通过fail指针进行回溯,所以在开始匹配前处理好结束标记就行。

利用好数组模拟栈的特性,不要一个一个pop。

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 char s[100005],word[100005];
 5 int n,cnt,last[100005],bj[100005],t[100005][26],fail[100005],fin[100005];
 6 int q[100005],q1,q2,leng,stack[100005],top;
 7 void insert(char *ss){
 8     int p=0,len=strlen(ss);
 9     for(int i=0;i<len;++i)
10         if(t[p][ss[i]-'a'])p=t[p][ss[i]-'a'];
11         else p=t[p][ss[i]-'a']=++cnt;
12     fin[p]=len;
13 }
14 void bfs(){
15     q1=1;for(int i=0;i<=25;++i)if(t[0][i])q[++q2]=t[0][i];
16     for(;q1<=q2;++q1)for(int i=0;i<=25;++i)
17         if(t[q[q1]][i])fail[q[++q2]=t[q[q1]][i]]=t[fail[q[q1]]][i];
18         else t[q[q1]][i]=t[fail[q[q1]]][i];
19 }
20 void find(){
21     int p=0,k;
22     for(int i=0;i<leng;++i){
23         k=last[i]=p=t[p][s[i]-'a'];stack[++top]=i;
24         while(k){
25             if(fin[k]){
26                 p=last[stack[top-fin[k]+1]-1];
27                 for(int ii=1;ii<=fin[k];++ii)bj[stack[top]]=1,top--;
28                 break;
29             }
30             k=fail[k];
31         }
32     }
33 }
34 int main(){
35     //freopen("cen.in","r",stdin);
36     //freopen("cen.out","w",stdout);
37     scanf("%s%d",s,&n);leng=strlen(s);
38     for(int i=1;i<=n;++i)scanf("%s",word),insert(word);
39     bfs();find();
40     for(int i=0;i<leng;++i)if(!bj[i])putchar(s[i]);
41 }
考场错解
 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 char s[100005],word[100005];
 5 int n,cnt,last[100005],bj[100005],t[100005][26],fail[100005],fin[100005];
 6 int q[100005],q1,q2,leng,stack[100005],top;
 7 void insert(char *ss){
 8     int p=0,len=strlen(ss);
 9     for(int i=0;i<len;++i)
10         if(t[p][ss[i]-'a'])p=t[p][ss[i]-'a'];
11         else p=t[p][ss[i]-'a']=++cnt;
12     fin[p]=len;
13 }
14 void bfs(){
15     q1=1;for(int i=0;i<=25;++i)if(t[0][i])q[++q2]=t[0][i];
16     for(;q1<=q2;++q1)for(int i=0;i<=25;++i)
17         if(t[q[q1]][i])fail[q[++q2]=t[q[q1]][i]]=t[fail[q[q1]]][i];
18         else t[q[q1]][i]=t[fail[q[q1]]][i];
19 }
20 void find(){
21     int k=0;
22     for(int i=0;i<leng;++i){
23         k=last[i]=t[k][s[i]-'a'];stack[++top]=i;
24         if(fin[k]){
25             top-=fin[k];
26             k=last[stack[top]];
27             
28         }
29     }
30 }
31 int main(){
32     scanf("%s%d",s,&n);leng=strlen(s);
33     for(int i=1;i<=n;++i)scanf("%s",word),insert(word);
34     bfs();find();
35     for(int i=1;i<=top;++i)putchar(s[stack[i]]);
36 }
考后正解(4次修改)

T2:记忆的轮廓

一颗树,根节点编号为1,目标节点编号为n,其中1-n的简单路径上,编号依次递增,在[1,n]中,一共有n个节点。我们把编号在[1,n]的叫做正确节点,[n+1,m]的叫做错误节点。一个叶子,如果是正确节点则为正确叶子,否则称为错误叶子。莎缇拉要帮助昴到达贤者之塔,因此现在面临着存档位置设定的问题。
为了让昴成长为英雄,因此一共只有p次存档的机会,其中1和n必须存档。被莎缇拉设置为要存档的节点称为存档位置。当然不能让昴陷入死循环,所以存档只能在正确节点上进行,而且同一个节点不能存多次档。因为通往贤者之塔的路上有影响的瘴气,因此莎缇拉假设昴每次位于树上一个节点时,都会等概率选择一个儿子走下去。每当走到一个错误叶子时,再走一步就会读档。具体的,每次昴到达一个新的存档位置,存档点便会更新为这个位置(假如现在的存档点是i,现在走到了一个存档位置j>i,那么存档点便会更新为j)。读档的意思就是回到当前存档点。初始昴位于1,当昴走到正确节点n时,便结束了路程。莎缇拉想知道,最优情况下,昴结束路程的期望步数是多少?50<=p<=n<=700,m<=1500,T<=5。数据保证每个正确节点均有至少2个儿子,至多3个儿子。

全场爆零,数据范围没粘梯度,50%很好拿的也没人拿到,而我有看错了题目,0。

考场上其实已经想到了70%思路,但毕竟读错题了。

其中一种正解很抖机灵,存档点相距太远答案就会爆炸增长而存档机会又不少,设不会在相距40以上的点存档,就能把70变成AC

题解也有很多种,每种都值得学习。

 1 #include<cstdio>
 2 int n,m,p,ext[705],a,t,b;
 3 double times[705],dt[705][705],dp[705][705];
 4 inline double min(double a,double b){return a<b?a:b;}
 5 int main(){
 6     //freopen("memory.in","r",stdin);
 7     //freopen("memory.out","w",stdout);
 8     scanf("%d",&t);
 9     while(t--){
10         scanf("%d%d%d",&n,&m,&p);
11         for(int i=1;i<=n;++i)ext[i]=0;
12         for(int i=1;i<=m-n;++i){
13             scanf("%d%d",&a,&b);
14             if(a<=n)ext[a]++;
15             if(b<=n)ext[b]++;
16         }
17         for(int i=1;i<=n;++i)ext[i]++;
18         for(int i=2;i<=n;++i){
19             times[i]=1;
20             for(int j=i-1;j;--j)
21                 times[j]=times[j+1]*ext[j],dt[j][i]=dt[j+1][i]+times[j]/ext[j]+times[j]*2*(ext[j]-1)/ext[j];
22         }
23         for(int i=1;i<=700;++i)for(int j=1;j<=700;++j)dp[i][j]=1e10;
24         dp[1][1]=0;
25         for(int i=1;i<n;++i)for(int j=1;j<=i;++j)for(int k=i+1;k<=n;++k)dp[k][j+1]=min(dp[k][j+1],dp[i][j]+dt[i][k]);
26         printf("%.4lf",dp[n][p]);
27     }
28     
29 }
考场错解
 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 #define mm(a) memset(a,0,sizeof(a))
 5 int n,m,p,a,b,t;double dt[1505][1505],g[1505],tot[1505],dp[1505][1505];int fir[1505],to[1530],l[1530],cnt,s[1505];
 6 inline double min(double a,double b){return a<b?a:b;}
 7 void connect(int a,int b){l[++cnt]=fir[a];fir[a]=cnt;to[cnt]=b;}
 8 void dfs(int p){dt[p][p]=0;
 9     for(int i=fir[p];i;i=l[i]){
10         dfs(to[i]),s[p]++;
11         if(p>n)g[p]+=g[to[i]];
12     }
13     if(p>n)if(s[p])g[p]=g[p]/s[p]+1;else g[p]=1;
14     if(p<=n)for(int i=fir[p];i;i=l[i])tot[p]+=g[to[i]];
15 }
16 int main(){//freopen("1.in","r",stdin);
17     scanf("%d",&t);
18     while(t--){
19         scanf("%d%d%d",&n,&m,&p);
20         cnt=0;mm(tot);mm(g);mm(s);mm(fir);
21         for(int i=1;i<=n;++i)for(int ap=1;ap<=p;++ap)dp[i][ap]=1e20;dp[1][1]=0;
22         for(int i=1;i<=m-n;++i)
23             scanf("%d%d",&a,&b),connect(a,b);
24         for(int i=1;i<n;++i)connect(i,i+1);
25         dfs(1);
26         for(int i=1;i<=n;++i)
27             for(int j=i+1;j<=i+40&&j<=n;++j)
28                 dt[i][j]=dt[i][j-1]*s[j-1]+s[j-1]+tot[j-1];
29         for(int i=2;i<=n;++i)
30             for(int j=((i-40>=1)?i-40:1);j<i;++j)
31                 for(int ap=2;ap<=i;++ap)
32                     dp[i][ap]=min(dp[i][ap],dp[j][ap-1]+dt[j][i]);
33         printf("%.4lf\n",dp[n][p]);
34     }
35 }
考后正解(6次修改)

T3:雨天的尾巴

N个点,形成一个树状结构。有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成所有发放后,每个点存放最多的是哪种物品。

1<=N,M<=100000,1<=a,b,x,y<=N,1<=z<=1e99​​

树上权值线段树动态开点+树上差分,考场上想出了树上差分可是不会弄,纯暴力50。

差分是从下往上,不是从根往下捯!这回彻底记住了。

改的时候线段树合并打错。。。忘了直接继承节点了而是此次都新建,M->R->M->R...

 1 #include<cstdio>
 2 #include<map>
 3 using namespace std;
 4 int f[5001][13],fir[5001],l[10001],to[10001],cnt,dep[10001],res;
 5 int ta[100001],tb[100001],tk[100001],lwb[5001],kind,a,b,LCA,n,mm;
 6 int have[5001][5001],ref[5001];
 7 map<int,int>m;
 8 void connect(int a,int b){
 9     l[++cnt]=fir[a];fir[a]=cnt;to[cnt]=b;
10     l[++cnt]=fir[b];fir[b]=cnt;to[cnt]=a;
11 }
12 void dfs(int p){
13     for(int i=1;i<=12;++i)f[p][i]=f[f[p][i-1]][i-1];
14     for(int i=fir[p];i;i=l[i])if(to[i]!=f[p][0])f[to[i]][0]=p,dep[to[i]]=dep[p]+1,dfs(to[i]);
15 }
16 int lca(int a,int b){
17     if(dep[a]<dep[b])res=a,a=b,b=res;
18     for(int dt=dep[a]-dep[b];dt;dt-=dt&-dt)a=f[a][lwb[dt&-dt]];
19     if(a==b)return a;
20     for(int i=12;i>=0;--i)if(f[a][i]!=f[b][i])a=f[a][i],b=f[b][i];
21     return f[a][0];
22 }
23 int main(){
24     //freopen("tail.in","r",stdin);
25     //freopen("tail.out","w",stdout);
26     for(int i=0;i<=12;++i)lwb[1<<i]=i;
27     scanf("%d%d",&n,&mm);
28     for(int i=1;i<n;++i)scanf("%d%d",&a,&b),connect(a,b);
29     for(int i=1;i<=mm;++i){
30         scanf("%d%d%d",&ta[i],&tb[i],&tk[i]);
31         if(m.find(tk[i])==m.end())m[tk[i]]=++kind,ref[kind]=tk[i];
32         tk[i]=m[tk[i]];
33     }
34     dfs(1);
35     for(int i=1;i<=mm;++i){
36         LCA=lca(ta[i],tb[i]);
37         for(int ii=ta[i];ii!=LCA;ii=f[ii][0])have[ii][tk[i]]++;
38         for(int ii=tb[i];ii!=LCA;ii=f[ii][0])have[ii][tk[i]]++;
39         have[LCA][tk[i]]++;
40     }
41     for(int i=1;i<=n;++i){
42         int ans=0;
43         for(int j=1;j<=kind;++j)if(have[i][j]>have[i][ans]||(have[i][j]==have[i][ans]&&ref[j]<ref[ans]))ans=j;
44         printf("%d\n",ref[ans]);
45     }
46 }
考场错解
 1 #include<cstdio>
 2 #include<map>
 3 #include<algorithm>
 4 using namespace std;
 5 inline int max(int a,int b){return a>b?a:b;}
 6 int f[100001][19],fir[100001],l[200001],to[200001],cntt,dep[100001],res;
 7 int ta[100001],tb[100001],tk[100001],lwb[300001],kind,a,b,LCA,n,mm;
 8 int ref[100001],ans[100001];
 9 int w[15000000],lc[15000000],rc[15000000],cnt=100000;
10 int bf[100001];
11 map<int,int>m;
12 void connect(int a,int b){
13     l[++cntt]=fir[a];fir[a]=cntt;to[cntt]=b;
14     l[++cntt]=fir[b];fir[b]=cntt;to[cntt]=a;
15 }
16 void dfs(int p){
17     for(int i=1;i<=18;++i)f[p][i]=f[f[p][i-1]][i-1];
18     for(int i=fir[p];i;i=l[i])if(to[i]!=f[p][0])f[to[i]][0]=p,dep[to[i]]=dep[p]+1,dfs(to[i]);
19 }
20 int lca(int a,int b){
21     if(dep[a]<dep[b])res=a,a=b,b=res;
22     for(int dt=dep[a]-dep[b];dt;dt-=dt&-dt)a=f[a][lwb[dt&-dt]];
23     if(a==b)return a;
24     for(int i=18;i>=0;--i)if(f[a][i]!=f[b][i])a=f[a][i],b=f[b][i];
25     return f[a][0];
26 }
27 void add(int &p,int l,int r,int pos,int ww){
28     if(!p)p=++cnt;
29     if(l==r){w[p]+=ww;return;}
30     int mid=l+r>>1;
31     if(pos>mid)add(rc[p],mid+1,r,pos,ww);
32     else add(lc[p],l,mid,pos,ww);
33     w[p]=max((lc[p]?w[lc[p]]:0),(rc[p]?w[rc[p]]:0));
34 }
35 int find_ans(int p,int l,int r){
36     if(!w[p])return 0;
37     if(l==r)return l;
38     int mid=l+r>>1;
39     if(lc[p]&&w[p]==w[lc[p]])return find_ans(lc[p],l,mid);
40     else return find_ans(rc[p],mid+1,r);
41 }
42 void merge(int p,int l,int r,int &fa){
43     int mid=l+r>>1;if(!fa)fa=++cnt,printf("%d %d %d %d\n",p,l,r,cnt);
44     if(l==r){w[fa]+=w[p];return;}
45     if(lc[p])if(lc[fa])merge(lc[p],l,mid,lc[fa]);else lc[fa]=lc[p];
46     if(rc[p])if(rc[fa])merge(rc[p],mid+1,r,rc[fa]);else rc[fa]=rc[p];
47     w[fa]=max((lc[fa]?w[lc[fa]]:0),(rc[fa]?w[rc[fa]]:0));
48 }
49 void dfs_ans(int p){
50     for(int i=fir[p];i;i=l[i])if(to[i]!=f[p][0])dfs_ans(to[i]);
51     ans[p]=find_ans(p,1,kind);if(f[p][0])merge(p,1,kind,f[p][0]);
52 }
53 int main(){
54     for(int i=0;i<=18;++i)lwb[1<<i]=i;
55     scanf("%d%d",&n,&mm);
56     for(int i=1;i<n;++i)scanf("%d%d",&a,&b),connect(a,b);
57     for(int i=1;i<=mm;++i)scanf("%d%d%d",&ta[i],&tb[i],&tk[i]),bf[i]=tk[i];
58     sort(bf+1,bf+1+mm);
59     for(int i=1;i<=mm;++i)if(m.find(bf[i])==m.end())m[bf[i]]=++kind,ref[kind]=bf[i];
60     for(int i=1;i<=mm;++i)tk[i]=m[tk[i]];
61     dfs(1);
62     for(int i=1;i<=mm;++i){
63         LCA=lca(ta[i],tb[i]);
64         add(ta[i],1,kind,tk[i],1);add(tb[i],1,kind,tk[i],1);
65         add(LCA,1,kind,tk[i],-1);add(f[LCA][0],1,kind,tk[i],-1);
66     }
67     dfs_ans(1);
68     for(int i=1;i<=n;++i)printf("%d\n",ref[ans[i]]);
69 }
考后正解(23次修改)

你很弱诶,你真的很弱诶。啥都不会打,暴力骗分总分还干不过T1一个hash。

考场上心态太自信了吧,T1打完过样例之后又手模了4,5组都没问题。就往后走了

T2,T3寻思着T1应该稳了,100分rank也不低就飘了。

平时打代码要注重理解。。。不要着急赶进度,注重积累,记住每一个小知识点,谁知道什么时候会有用

难题可以不打,简单题必须AC,暴力对拍检查低错,先稳后强。

加油吧,还有机会,小心被干到第二机房。

猜你喜欢

转载自www.cnblogs.com/hzoi-DeepinC/p/11057937.html