考后反思(bzoj3940 bzoj4899 bzoj3307)

考试的时候用哈希水过了第一题本来想用哈希只可以得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 }


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 }

原文地址:https://www.cnblogs.com/znsbc-13/p/11072767.html

时间: 2024-07-31 15:52:46

考后反思(bzoj3940 bzoj4899 bzoj3307)的相关文章

考后反思8.05

话说我前两次考后反思还没有写,晚上补吧(咕咕咕的气息) 考试过程 先把所有题看了看,t1没什么思路,t2好像是个傻逼大模拟,t3好像是个原题只是稍微改变了但我那个原题还没过啊! 先做t3,想到了和奇袭差不多,我随手打了个线段树,然后对拍全对,我觉得52分稳了(事实上我暴力打错了) 然后开始钢t2,傻逼大模拟只要打对分还是挺高的,然后t2一看数据范围1e9.找个循环节不就完了吗. 对于我来说打傻逼大模拟一直是煎熬的过程,但这次我打起来比较轻松,找循环节也找对了,对拍再次全对,我又觉得50分稳了 然

考后反思

分享我挂掉的经验 我考虑到了两个相连,三个相连,1个单独 然后没考虑到这个 题目里都给了 改完80分 第一题 都是考完试立马就发现的错误,还没有看题解自己突然想到自己的错误. #include<bits/stdc++.h> using namespace std; #define ll long long #define A 100000 ll a,b,x,y,aa,bb,cc,t; ll exgcd(ll a,ll b,ll &x,ll &y) { if(b==0) { x=

考后反思8.10

考试先打的t2,照例先打数据结构题的暴力,然后再想正解,然后打t1,我想这个题跟蜥蜴差不多,那就打个网络流吧 t1 我把这个题想的十分复杂 打了个网络流 网络流做法: //网络流我不会打一个题也没打过,甚至没打过模板,但我还是打了网络流,但样例过了 //简称青蛙为蓝毒 //建立超级原点,与每一只蓝毒相连,边权为1 //每一只蓝毒与距离起点<D相连 //每一只蓝毒自己拆点,自己与自己相连边权为1 //石块与石块之间边权Inf //石块最后与终点相连 我知道它过不了全部点,我觉得至少60分吧.然后他

考后反思8.9

三个题读错两道,...... 在信息学奥赛里题量少,分数多,读错题就意味着你这个整个题拿不到什么分,一下拉开很大分差. t2,一个傻逼大水题,无脑缩点最长链,我读错了 如果存在两个不同的城市 i,j ,它们在同一轮被轰炸,并且可以通过地道从城市i到达城市j,那么城市i的间谍可能因为撤离到城市j而被炸死.为了避免这一情况,战狂不会在同一轮轰炸城市i 和城市 j . 仔细品读这句话. 我以为相邻的不可炸,然后我以为这个题特别难 然后我就开始刚它 首先奇环要炸三次,偶环炸两次,环加链分情况,奇环+奇链

【自考】信息系统开发与管理(三)——考后总结

考完试了,对这维持三个左右的自考学习做了一个总结,不管结果如何,我都有很大的收获.接下来,就要对这三本书做一下考后总结. <信息系统资源管理>这本书是我学起来最有乐趣的一本书,里面的知识点,既可以和我们刚做的机房联系起来,又和我们的日常生活学习相关联,织网很容易,也不容易忘,下面就对这本书再做一下大体的总结吧! 一.导图: 二.解释说明 这本书可以总结为:信息系统开发管理=信息+系统+开发+管理,书中介绍的最多的还是开发,但是没有前面的信息,系统,管理,是给后面的开发最铺垫的. 在开发这一部分

《阿里巴巴编码规范(JAVA)》认证考后感

2018.02.15除夕拿下了阿里云认证的<阿里巴巴编码规范(JAVA)>认证,写下这篇考后感,记录考试中碰到的一些考点. 先总体介绍下这个考试规则,50道选择题,大部分是多选题,有少部分单选,满分100分,达到80分即可拿到证书. 传送门:https://edu.aliyun.com/certification/cldt02 绝大部分的考题涉及到的知识点都能在<阿里巴巴JAVA开发手册>上找到,这些都是比较基础的考点,相信对大多数有工作经验的猿们来说,不是难题,这一部分笔者就不再

2015阿里巴巴前端实习生在线笔试考后总结

写在前面 还是太年轻,第一次在线笔试有些紧张了 一.2015题目 我遇到的题目:6个选择其中3个多选,1个填空,6个大题.客服姐姐说题目是随机给的(因为给了一个时段考试,而不是统一时间点开考),不过题型应该是固定的. 单选:一个数组,两个引用,相互赋值,问输出 眩晕抗性-30% 单选:问一个return匿名函数的函数的执行结果,内部还有apply 眩晕抗性再-69% 单选:问字符串替换结果是什么,当然,又是套了几层,绕了几圈 眩晕抗性再-1%,嗯,做完这道给彻底绕晕了 多选:移动端,如果A按钮上

【自考】数据库系统原理(三)——考后总结

感觉数据库这本书特别有用,有些知识在考试前,还不是太理解,需要多多去比较,总结.其实,每本书都很有用的,只不过这本书对于我们刚刚学过的SQL来说更有用一些.既是知识的补充,又可以当做复习!考数据库的时候,中午没回学校,也没休息,头脑很不清醒,现在头脑清醒了,赶紧再做个总结吧! 一.导图 二.解释说明 (1)这本书讲了两个发展,一头一尾,一个数据库系统,一个数据库技术.重头戏是数据库设计与数据库管理. (2)在数据库设计中,包含了ER模型,关系模型以及ER模型与关系模型的转换:关系模型变成关系模式

8.9~8.?考后总结

8.9 rank 7/56 T1看了会儿发现n^3暴力很水,稍一优化就成n^2了,所以半个小时就码出来还顺便对拍, 然后看T2,很明显的tarjan+拓扑,我当时觉得DFS好打就没打拓扑,T了,白扔40分 自己造了个样例,手模一会,然后也懒得打对拍了QAQ 发现刚过了不到两个小时,上了趟厕所(听某nc大佬和某kx说考试上厕所会使你灵感倍增,于是我信了??) 回来后发现T1有可能是容斥,然而我没推出来(太蒟蒻了orz大佬们都推出来了,果然我数学就是个坑) 最后一个小时开始肝T3毒瘤题,dp不会推,