2017-10-29离线赛总结

来源:互联网 发布:损坏文件修复软件 编辑:程序博客网 时间:2024/06/03 14:52

失分小结:
估分: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 20vector<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 2005template<class _>void chk_mi(_ &x,_ y){if(x>y||x==-1)x=y;}double P[M],dp[2][M][M];int dis[N][N],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][n][i]!=-1)chk_mi(ans,dp[0][n][i]);    for(int i=0;i<=m;i++)if(dp[1][n][i]!=-1)chk_mi(ans,dp[1][n][i]);    printf("%.2f\n",ans);    return 0;}
原创粉丝点击