考后反思(bzoj3940bzoj4899bzoj3307)(代码片段)

znsbc-13 znsbc-13     2022-12-22     477

关键词:

考试的时候用哈希水过了第一题本来想用哈希只可以得20左右没想到由于数据过于水A了

然后雨天的尾巴骗了5分,总分105 我太菜了

首先时间分配的不合理:第一题大水题ac自动机打完了都不会,第二题略微想了想打了个高斯消元,然后样例没过......,最后输出了一个随机数,第三题(lca板子忘了,打错一个地方,没有调出来)最后骗了五分

 

考后主要讲一下第二题:记忆的轮廓(bzoj4899)和第三题:雨天的尾(yi)巴(bzoj3307)


 

Censoring

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

没什么好讲的,ac自动机然后开栈维护


 

记忆的轮廓

 

内存限制:512 MiB 时间限制:1000 ms 标准输入输出
 
 
 
 
 
 
 

 

 

题目描述

通往贤者之塔的路上,有许多的危机。
我们可以把这个地形看做是一颗树,根节点编号为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

这个题还是挺有意思的

题目中提到这一句话
““我们可以把这个地形看做是一颗树,根节点编号为1,目标节点编号为n,其中1-n的简单路径上,编号依次递增,在[1,n]中,一共有n个节点。我们把编号在[1,n]的叫做正确节点,[n+1,m]的叫做错误节点。””
那么题目中就暗示了1--n的路径肯定是一条链

首先题目中说简单路径
其次具体可以反证出来
比如假设有三个点1-2 1-3 各有一条边那么1-3的简单路径就只有两个节点与n(n==3)个节点矛盾所以1-n的路径一定是一条链

这一个小点一定要读出来

设d[i]为i的出度,g[i]为错误儿子i返回存档期望步数,s[i]为当前点走到所有错误节点g之和

设a[i][j]表示以i为最新存档点走到j时期望步数,f[i][j]为以i为下一个存档点当前还剩余j个存档点

我们逆着转移f,f可以由任意一个在i之后的点并且剩余存档数量为j-1的f贡献

然后分析 这个dp实际上就是在1-n一条链上进行的, 那么我们其实就可以写出一个”类似“于线性dp的方程式

f[i][j]=min(f[i][j],f[k][j-1]+a[i][k])

这里a数组求法分析

设c是从j-1走到j的期望步数

a[i][j]=a[i][j-1]+c

分析

首先1/d[j-1]概率走到正确节点

其他可以由首先走到错误节点son

然后返回存档i,再继续走一个a[i][j-1],然后再加上从j-1走到j的期望步数

这里有一个注意点 这里的c在Σ中要加一(走到错误节点要走一步)

于是

c=1/d[j-1]+Σ(g[son]+a[i][j-1]+c+1) ;//        (son表示j-1的错误儿子)

分析我们将所有g相加就是s

c=(1/d[j-1])+(d[j-1]-1)/d[j-1]+(1/d[j-1])*s[j-1]+((d[j-1]-1)/d[j-1])*a[i][j-1]+((d[j-1]-1)/d[j-1])*c;

移项

1/d[j-1]*c=1+1/d[j-1]*s[j-1]+((d[j-1]-1)/d[j-1])*a[i][j-1];

首先要预处理出走到错误节点返回的期望,具体可以通过一个简单dfs处理

然后我们再次相乘得出

c=d[j-1]+s[j-1]+(d[j-1]-1)*a[i][j-1];

最后相加

得出

a[i][j]=a[i][j-1]*d[j-1]+d[j-1]+s[j-1];

然后

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

那么我们推测对于a数组来说 它的快速增长肯定会爆

然后我们记录一个step,推测每次转移大致最大相差40步左右(但我觉得这么做是qj测试点)

然后就有了if(k-i>40) break;

 经过实际测试(由于测试点过水) k-i 取到20左右就可以了

以下是本人丑陋的代码

技术图片
 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define db double
 4 #define A 2500
 5 using namespace std;
 6 ll t,tot=0,n,m,p,head[A],nxt[A],ver[A];
 7 db g[A],a[A][A],cur,f[A][A],d[A],s[A];
 8 bool flag[A];
 9 inline void add(ll x,ll y)
10 nxt[++tot]=head[x];head[x]=tot;ver[tot]=y;
11 inline ll read()
12 
13     ll x=0,f=1;char c=getchar();
14     while(!isdigit(c))
15     
16         if(c==-)
17         f=-1;
18         c=getchar();
19     
20     while(isdigit(c))
21     
22         x=(x<<1)+(x<<3)+c-0;
23         c=getchar();
24     
25     return f*x;
26 
27 void dfs(ll x)
28 
29     flag[x]=1;
30     g[x]=1.0;
31     for(ll i=head[x];i;i=nxt[i])
32     
33         ll y=ver[i];
34         if(!flag[y])
35             dfs(y);
36         g[x]+=1.0/d[x]*g[y];
37     
38 
39 int main()
40 
41     t=read();
42     while(t--)
43         
44         tot=0;
45         memset(flag,0,sizeof(flag));
46         memset(head,0,sizeof(head));
47         memset(nxt,0,sizeof(nxt));
48         memset(ver,0,sizeof(ver));
49         memset(d,0,sizeof(d));
50         memset(g,0,sizeof(g));
51         memset(flag,0,sizeof(flag));
52         memset(f,125,sizeof(f));
53         n=read();m=read();p=read();
54         for(ll i=1;i<=m-n;i++)
55         
56             ll x,y;
57             x=read(),y=read();
58             add(x,y);d[x]++;
59         
60         for(ll i=1;i<n;i++)
61             d[i]++;
62         for(ll i=1;i<=n;i++)
63             if(!flag[i])dfs(i);
64         for(ll i=1;i<=n;i++)
65         
66             s[i]=0;
67             for(ll j=head[i];j;j=nxt[j])
68             
69                 ll y=ver[j];
70                 s[i]+=g[y];
71             
72         
73         for(ll i=1;i<=n;i++)
74             
75             a[i][i]=0;
76             for(ll j=i+1;j<=n;j++)
77                 a[i][j]=a[i][j-1]*d[j-1]+s[j-1]+d[j-1];
78             
79         f[n][1]=0.0;    
80         for(ll j=2;j<=p;j++)
81             for(ll i=1;i<=n;i++)
82                 for(ll k=i+1;k<=n;k++)
83                 
84                     if(k-i>40) break;
85                     f[i][j]=min(f[i][j],f[k][j-1]+a[i][k]);
86                 
87         db ans=f[1][p];
88         printf("%.4lf\n",ans);    
89     
90     return 0;
91 
View Code

 


 

C. 雨天的尾巴

内存限制:128 MiB 时间限制:1000 ms 标准输入输出
 
 
 
 
 
 
 
 
 
 

题目描述

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^910?9??

也是一道不错的题

思考我们如果按照既定套路,进行树上拆分的话

我们还需要维护每一个节点出现的值中最大的是什么  

我们首先可以想到开一个v[n][max_size]数组

然后要i至j的z值+1就

v[i][z]++,v[j][z]++,v[lca][z]--,v[f[lca][0]][z]--;

如果只是简单开数组会MLE+TLE

为了省时间+省空间

我们可以建立n棵权值线段树

如果我们不举行别的措施仍然会MLE,故使用动态开点线段树

另外由于值特别大而我们开的是权值线段树,我们可以进行离散化也可以采取”别的操作“

别的操作:具体来说例如有m组询问,我们值域只需要开到m    其实还是和离散化差不多

最后统一进行线段树合并

完了(数据结构题真不知道要说些什么)

以下依然是本人丑陋的代码

技术图片
  1 #include<bits/stdc++.h>
  2 #define A 100005
  3 #define ll int
  4 using namespace std;
  5 bool flag[A*2];
  6 ll cnt=0,Ans[A*60],ans[A*60],deep[A*2],f[A][24],head[A*2],next[A*2],ver[A*2],lc[A*60],rc[A*60],tot=0,T[A*60];
  7 ll n,m,sum[A];
  8 inline ll read()
  9 
 10     ll f=1,x=0;char c=getchar();
 11     while(!isdigit(c))
 12     
 13         if(c==-) f=-1;
 14         c=getchar();
 15     
 16     while(isdigit(c))
 17     
 18         x=x*10+c-0;
 19         c=getchar();
 20     
 21     return f*x;
 22 
 23 void pushup(ll now)
 24 
 25     if(ans[lc[now]]>=ans[rc[now]])
 26     ans[now]=ans[lc[now]],Ans[now]=Ans[lc[now]];
 27     else
 28     ans[now]=ans[rc[now]],Ans[now]=Ans[rc[now]];
 29 
 30 void add(ll x,ll y)
 31 
 32     next[++tot]=head[x];
 33     head[x]=tot;
 34     ver[tot]=y;
 35 
 36 ll merge(ll x,ll y,ll l,ll r)
 37 
 38     if(l==r&&x&&y) ans[x]+=ans[y];
 39     if(!x||!y) return y+x;
 40     ll mid=(l+r)>>1;
 41     lc[x]=merge(lc[x],lc[y],l,mid);
 42     rc[x]=merge(rc[x],rc[y],mid+1,r);
 43     if(l!=r)pushup(x);
 44     return x;
 45 
 46 void change(ll &p,ll l,ll r,ll pos,ll v)
 47 
 48     if(!p) p=++cnt;
 49     if(l==r)
 50     ans[p]+=v;Ans[p]=l;return ;
 51     ll mid=(l+r)>>1;
 52     if(pos<=mid) change(lc[p],l,mid,pos,v);
 53     else change(rc[p],mid+1,r,pos,v);
 54     if(l!=r) pushup(p);
 55 
 56 void dfs(ll x,ll dep)
 57 
 58     flag[x]=1,deep[x]=dep;
 59     for(ll i=head[x];i;i=next[i])
 60     
 61         ll y=ver[i];
 62         if(flag[y]) continue;
 63         f[y][0]=x;
 64         deep[y]=dep;
 65         dfs(y,dep+1);
 66     
 67 
 68 ll lca(ll x,ll y)
 69 
 70     if(deep[x]>deep[y])
 71         swap(x,y);
 72     for(ll i=20;i>=0;i--)
 73     
 74         if(deep[x]<=deep[f[y][i]])
 75             y=f[y][i];
 76         if(deep[x]==deep[y]) break;
 77     
 78     if(x==y) return x;
 79     for(ll i=20;i>=0;i--)
 80     
 81         if(f[x][i]!=f[y][i])
 82             x=f[x][i],y=f[y][i];
 83     
 84     return f[x][0];
 85 
 86 void dfs_(ll x)
 87 
 88     flag[x]=1;
 89     for(ll i=head[x];i;i=next[i])
 90     
 91         ll y=ver[i];
 92         if(flag[y]) continue;
 93         dfs_(y);
 94         T[x]=merge(T[x],T[y],1,A);
 95     
 96     if(ans[T[x]]>0)
 97         sum[x]=Ans[T[x]];
 98 
 99 int main()
100 
101     n=read(),m=read();
102     for(ll i=1;i<n;i++)
103     
104         ll xx=read(),yy=read();
105         add(xx,yy);
106         add(yy,xx);
107     
108     dfs(1,1);
109     f[1][0]=0;
110     for(ll i=1;i<=20;i++)
111         for(ll j=1;j<=n;j++)
112             f[j][i]=f[f[j][i-1]][i-1];
113     ll LCA;
114     for(ll i=1;i<=m;i++)
115     
116         ll x=read(),y=read(),z=read();
117         LCA=lca(x,y);
118         change(T[x],1,A,z,1);
119         change(T[y],1,A,z,1);
120         change(T[LCA],1,A,z,-1);
121         change(T[f[LCA][0]],1,A,z,-1);
122     
123     memset(flag,0,sizeof(flag));
124     dfs_(1);
125     for(ll i=1;i<=n;i++)
126         printf("%d\n",sum[i]);
127 
View Code

 

bzoj3940&&bzoj3942

方法就是维护一个动态栈记录栈的每一位匹配到串的哪一位的编号第一道kmp第二道ac自动机自己理会#include<cstdio>#include<cstring>#include<algorithm>usingnamespacestd;constintM=1000055;charstack[M],s[M],t[M],f[M],next[M];intlen,top; 查看详情

bzoj3940[usaco2015feb]censoring

DescriptionFarmerJohnhaspurchasedasubscriptiontoGoodHooveskeepingmagazineforhiscows,sotheyhaveplentyofmaterialtoreadwhilewaitingaroundinthebarnduringmilkingsessions.Unfortunately,thelatestissuecontain 查看详情

bzoj3940censoring

把上题的KMP改成AC自动机。注意root必须是0。因为root其实是NULL的意思。#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<queue>#definemaxn500050usingnamespacestd;chart[m 查看详情

bzoj3940[usaco2015feb]censoring*

bzoj3940[Usaco2015Feb]Censoring题意:有一个S串和一大堆T串,不断地在S串里找最早出现的T串,然后将其删除。S串≤100000,T串总长度≤100000。题解:对所有T串建AC自动机,然后同bzoj3942。注意,本题的AC自动机必须利用所有fail函数建成... 查看详情

bzoj3940

AC自动机复习一下。。。可惜又写错了我们发现就是把单词建成ac自动机,然后把串在ac自动机上跑一遍,每到一个单词结束点就删除,删除是利用栈,每次弹出单词长度个字符就可以了发现两个小问题,strlen很慢,不能写在循环... 查看详情

bzoj3940censoring题解(ac自动机)(代码片段)

题目描述FarmerJohnhaspurchasedasubscriptiontoGoodHooveskeepingmagazineforhiscows,sotheyhaveplenty ofmaterialtoreadwhilewaitingaroundinthebarnduringmilkingsessions.Unfortunately,thelatest issueco 查看详情

bzoj3940:[usaco2015feb]censoring--ac自动机

3940:[Usaco2015Feb]CensoringTimeLimit: 10Sec  MemoryLimit: 128MBDescriptionFarmerJohnhaspurchasedasubscriptiontoGoodHooveskeepingmagazineforhiscows,sotheyhaveplenty ofmaterial 查看详情

bzoj4899--记忆的轮廓

Description通往贤者之塔的路上,有许多的危机。我们可以把这个地形看做是一颗树,根节点编号为1,目标节点编号为n,其中1-n的简单路径上,编号依次递增,在[1,n]中,一共有n个节点。我们把编号在[1,n]的叫做正确节点,[n+1,m]... 查看详情

[bzoj3940][usaco2015feb]censoring

最近做题成双成对?不是双倍经验就是两题同解。3940  3942给定字典,给定字符串,删去字符串中所有字典内单词。保证不会出现二者包含状况。$nleq1e5,sumlenleq1e5$AC自动机裸题。build出AC自动机后从左到右插入文本串,同时... 查看详情

bzoj3940:[usaco2015feb]censoring

给个长度<=1e5的串s,再给n个模板串总长不超1e5,每次把s中起始位置最早的一个模板串删掉,求最后剩的串。AC自动机,开个栈记一下每次走到哪里,匹配成功后直接在栈里找到这一串的初始位置对应自动机上的节点,从而回... 查看详情

bzoj3940[usaco2015feb]censoring

【题目描述】FJ把杂志上所有的文章摘抄了下来并把它变成了一个长度不超过10^5的字符串S。他有一个包含n个单词的列表,列表里的n个单词记为t_1...t_N。他希望从S中删除这些单词。 FJ每次在S中找到最早出现的列表中的单词(... 查看详情

loj6171/bzoj4899记忆的轮廊(期望dp+优化)

题目:https://loj.ac/problem/6171分析:设dp[i][j]表示从第i个点出发(正确节点),还可以有j个存档点(在i点使用一个存档机会),走到终点n的期望步数那么a[i][k]表示i点为存档点,从i点走到k点(正确节点)的期望步数(中间没有... 查看详情

bzoj4899记忆的轮廓题解(概率dp+决策单调性优化)(代码片段)

题目背景四次死亡轮回后,昴终于到达了贤者之塔,当代贤者夏乌拉一见到昴就上前抱住了昴“师傅!你终于回来了!你有着和师傅一样的魔女的余香,肯定是师傅”。众所周知,大贤者是嫉妒魔女沙提拉的老公,400年前... 查看详情

bzoj1088:[scoi2005]扫雷mine

1088:[SCOI2005]扫雷MineTimeLimit:10Sec  MemoryLimit:162MBSubmit:3940  Solved:2324[Submit][Status][Discuss]Description  相信大家都玩过扫雷的游戏。那是在一个n*m的矩阵里面有一些雷,要你根据一些信息找出雷来。万圣节到了,“余&... 查看详情

bzoj1096[zjoi2007]仓库建设(斜率优化)

1096:[ZJOI2007]仓库建设TimeLimit: 10Sec  MemoryLimit: 162MBSubmit: 3940  Solved: 1736Description  L公司有N个工厂,由高到底分布在一座山上。如图所示,工厂1在山顶,工厂N在山脚。由于这座山处于高原内陆地区(... 查看详情

bzoj5017[snoi2017]炸弹

...区间,所以记录每个节点的左端点和右端点合并时取最值反思:思维定式,以为求解可达点个数不能合并/**************************************************************Problem:5017User:ws_zzyer 查看详情

hzwer的bzoj题单

counter:664BZOJ1601BZOJ1003BZOJ1002BZOJ1192BZOJ1303BZOJ1270BZOJ3039BZOJ1191BZOJ1059BZOJ1202BZOJ1051BZOJ1001BZOJ1588BZOJ1208BZOJ1491BZOJ1084BZOJ1295BZOJ3109BZOJ1085BZOJ1041BZOJ1087BZOJ3038BZOJ1821BZOJ1 查看详情

bzoj1143:[ctsc2008]祭祀river

...的边那么其他的点选的话就没有矛盾的了。符合题意、//反思:有向图根本没有联想到二分图,想的一直是暴力暴力暴力。。。以为数据那么小。。。应该联想有可能用上的算法。#include<cstdio>#include<cstring>#include<cctype&... 查看详情