您的位置:首页 > 其它

2017-10-29离线赛总结

2017-10-29 22:34 155 查看
失分小结:

估分:220

实际分数:205

第二题的有15分切错了,但总体上能把自己切的大部分分数给弄到还是不错的

(虽然这次的发挥并不是特别好,感觉考试全程敲暴力)

这次考试裸分应该是有(256)[100+80+76]

其实切分是很重要的

像机房里另外几个大佬对于第三题都是切m=0,1,2

而像我这样的蒟蒻切了好多鬼畜的:性质2,m=0,…

切得太杂了,所以并不能得多少分

第一题模拟题,但把我转的晕头转向整整写了半个小时

第二题看起来就像是道树上差分

可以发现每个点的讯问的点是唯一的,

然后观察数据可以知道复杂度不会超过nlogn

利用树上差分,可以把每条路径对应的值在遍历树的过程中算出来

对于同一深度,答案先减去遍历该子树前的,在遍历后在加回去,

这样就可以得出该子树对应深度的人数(类似于”王子”)

对于l点走到lca,可以较为容易地利用差分算出

但lca到r,会略有不同

我们可以把从l到lca再到r的过程看做从一个很高的fa到r的过程

这个fa的深度就是dep[r]-len len=dep[r]+dep[l]-dep[fa]*2

由于dep[r]-len可能是负数,所以可以取模强制转化成正数

代码实现:

#include<bits/stdc++.h>
using namespace std;

#define pb push_back
#define M 300005
#define S 20

vector<int>edge[M],W[2][M],V[2][M];
int T[M],dep[M],Fa[S][M],ans[M],SumL[M],SumR[M];
int n,m;

void Ldfs(int x,int f){
dep[x]=dep[f]+1;
Fa[0][x]=f;
for(int i=0;i<(int)edge[x].size();i++){
int y=edge[x][i];
if(y==f)continue;
Ldfs(y,x);
}
}

int LCA(int x,int y){
if(dep[x]>dep[y])swap(x,y);
int len=dep[y]-dep[x];
for(int i=0;i<S;i++){
if(len&(1<<i))y=Fa[i][y];
}
if(x==y)return x;
for(int i=S-1;i>=0;i--){
if(Fa[i][x]!=Fa[i][y]){
x=Fa[i][x];
y=Fa[i][y];
}
}
return Fa[0][x];
}

void Rdfs(int x){
int l=(dep[x]+T[x])%M;
int r=(dep[x]-T[x]+M)%M;
ans[x]-=SumL[l]+SumR[r];

for(int i=0;i<(int)edge[x].size();i++){
int y=edge[x][i];
if(y==Fa[0][x])continue;
Rdfs(y);
}

for(int i=0;i<(int)W[0][x].size();i++)SumL[W[0][x][i]]+=V[0][x][i];
for(int i=0;i<(int)W[1][x].size();i++)SumR[W[1][x][i]]+=V[1][x][i];
ans[x]+=SumL[l]+SumR[r];
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
edge[x].pb(y);
edge[y].pb(x);
}

Ldfs(1,0);
for(int i=1;i<S;i++)for(int j=1;j<=n;j++)Fa[i][j]=Fa[i-1][Fa[i-1][j]];

for(int i=1;i<=n;i++)scanf("%d",&T[i]);
for(int i=1;i<=m;i++){
int l,r,lca;
scanf("%d%d",&l,&r);
lca=LCA(l,r);
int dis=dep[l]+dep[r]-2*dep[lca];
W[0][Fa[0][lca]].pb(dep[l]);
V[0][Fa[0][lca]].pb(-1);
W[0][l].pb(dep[l]);
V[0][l].pb(1);
W[1][lca].pb((M+dep[r]-dis)%M);
V[1][lca].pb(-1);
W[1][r].pb((M+dep[r]-dis)%M);
V[1][r].pb(1);
}

Rdfs(1);
for(int i=1;i<=n;i++)printf("%d ",ans[i]);
puts("");
return 0;
}


第三题算是一道入门的期望题,虽然考试时没有去想正解

dp定义是 在原来的教室还是另一个教室 上第几节课 用了几个申请

根据期望的线性性质,我们可以单独算每一步的贡献什么鬼玩意,然后就可以每次取最优

代码实现如下(小丑):

#include<bits/stdc++.h>
using namespace std;
#define N 305
#define M 2005
template<class _>void chk_mi(_ &x,_ y){if(x>y||x==-1)x=y;}

double P[M],dp[2][M][M];
int dis

,Fi[M],Se[M];
int n,m,v,e;

void init(){
scanf("%d%d%d%d",&n,&m,&v,&e);
for(int i=1;i<=n;i++)scanf("%d",&Fi[i]);
for(int i=1;i<=n;i++)scanf("%d",&Se[i]);
for(int i=1;i<=n;i++)scanf("%lf",&P[i]);

memset(dis,-1,sizeof(dis));
for(int i=1;i<=e;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(x==y)continue;
chk_mi(dis[x][y],z);
chk_mi(dis[y][x],z);
}
//floyd
for(int k=1;k<=v;k++){
for(int i=1;i<=v;i++){
if(dis[i][k]==-1)continue;
for(int j=1;j<=v;j++){
if(dis[k][j]==-1)continue;
chk_mi(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
for(int i=1;i<=v;i++)dis[i][i]=0;
for(int i=1;i<=v;i++)dis[0][i]=0;
}

void DP(){
for(int i=0;i<=n;i++)for(int j=0;j<=m;j++)dp[1][i][j]=dp[0][i][j]=-1.0;
dp[0][0][0]=0;
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
if(j&&dp[0][i-1][j-1]!=-1)chk_mi(dp[1][i][j],dis[Fi[i-1]][Fi[i]]*(1-P[i]));
if(j&&dp[1][i-1][j-1]!=-1)chk_mi(dp[1][i][j],dp[1][i-1][j-1]+
(dis[Fi[i-1]][Se[i]]*P[i]+dis[Fi[i-1]][Fi[i]]*(1-P[i]))*(1-P[i-1]));
if(dp[0][i-1][j]!=-1)chk_mi(dp[0][i][j],dp[0][i-1][j]+dis[Fi[i-1]][Fi[i]]);
if(dp[1][i-1][j]!=-1)chk_mi(dp[0][i][j],dp[1][i-1][j]+dis[Se[i-1]][Fi[i]]*P[i-1]
+dis[Fi[i-1]][Fi[i]]*(1-P[i-1]));
}
}
}

int main(){
init();
DP();
double ans=-1;
for(int i=0;i<=m;i++)if(dp[0]
[i]!=-1)chk_mi(ans,dp[0]
[i]);
for(int i=0;i<=m;i++)if(dp[1]
[i]!=-1)chk_mi(ans,dp[1]
[i]);
printf("%.2f\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: