【NOIP2016】Day1

来源:互联网 发布:网络吃鸡是什么意思啊 编辑:程序博客网 时间:2024/06/01 23:05

Solution

T1

模拟,可以用异或简化代码

T2

这里讲一下正解,网上题解也有很多
我们把路径插成,u->lca , lca->v,
我们先看u->lca这一条,若这条路径上的点x能观察到u,那么:
deep[u]deep[x]=T[x]
移项后得:deep[u]=deep[x]+T[x]
发现右边是一个之与x有关的项,我们的目标就是求x的子树中有几个起点u,终点在x以上(含x),且deep[u]=deep[x]+T[x]
这句话让我们想到了什么?树上差分!
我们在u上+1,fa[lca]上-1,就表示了一条链,但这个值怎么搞?开一个桶就行了!
我们对每一个节点建一个类似边表的东西,表示会对那些节点+-1,也可以用vector,然后dfs到u时,遍历一遍这个边表,把他的影响算上,然后+a[T[u]+deep[u]],a是桶。
注意:一个节点可以有多个儿子,但每个儿子只能计数自己的子树内的个数,这样会多次计数,我们可以在进入这个节点前减去答案,最后再加答案,就是加差值,这很重要,也简化了步骤。
往上走也是一样,deep[u]deep[lca]+deep[y]deep[lca]=T[y]
移项后:T[y]deep[y]=deep[u]2deep[lca]

T3

这道题目赛场上写了一个本来能拿80的错误的DP,但是最短路打错了,只剩20.
对于这个期望有两种理解:一种是每条可能路径的长度*概率,
另外一种是:每两节课之间的每条路的长度*概率,
第二种理解的转化是解题的关键,因为这道题目只有相邻的点会影响路径的选择,所以我们要记录前一节课是在哪里上的,或者说是否申请,
http://www.cnblogs.com/ljh2000-jump/p/6189054.html 此人博客暴力写的都很详细
这显然是一道概率DP裸题。考虑f[i][j][0、1]表示前i堂课,已经申请了j次,这次申不申请的最小期望值
d1=dis[c[i-1]][c[i]],d2=dis[c[i-1]][d[i]],d3=dis[d[i-1]][c[i]],d4=dis[d[i-1]][d[i]];
f[i][j][0]=max{f[i-1][j][0]+d1,f[i-1][j][1]+d3*k[i-1]+d1*(1-k[i-1])}
表示i节课不申请,有两种来源:i-1节课不申请,只可用从c[i-1]走到c[i],i-1节课申请,分类,成功,概率k[i-1],价值d1*k[i-1],失败,概率(1-k[i]),价值d3 *(1-k[i-1]),其他同理。

CODE

T1

#include<bits/stdc++.h>using namespace std;const int MAXN=100000+10;int d[MAXN],n,m;char name[MAXN][15];int main(){    scanf("%d%d",&n,&m);    for (int i=0;i<n;i++)        scanf("%d%s",&d[i],&name[i]);    int now=0,x,y;    for (int i=0;i<m;i++)    {        scanf("%d%d",&x,&y);        if (d[now]^x) now=(now+y)%n;        else now=(now-y+n)%n;       }    puts(name[now]);        return 0;}

T2

#include<bits/stdc++.h>using namespace std;const int MAXN=300010;int Head[MAXN],Headq[MAXN],Headup[MAXN],Headdown[MAXN];int ans[MAXN],father[MAXN],deep[MAXN],a[MAXN],b[MAXN*2];int s[MAXN],t[MAXN],lca[MAXN],T[MAXN],fa[MAXN];int n,m,tot,tot1;bool vis[MAXN];struct Edge{    int v,next,x;}edge[MAXN*2];struct Ques{    int v,next,id;}que[MAXN*2];struct node{    int next,x,y;}up[MAXN*2],down[MAXN*2];void adde(int x,int y){    edge[++tot]=(Edge){y,Head[x],0};    Head[x]=tot;}void addq(int x,int y,int id){    que[++tot]=(Ques){y,Headq[x],id};    Headq[x]=tot;}void addup(int u,int x,int y){    up[++tot]=(node){Headup[u],x,y};    Headup[u]=tot;}void adddown(int u,int x,int y){    down[++tot1]=(node){Headdown[u],x,y};    Headdown[u]=tot1;}int getfa(int x){    return fa[x]==x?fa[x]:fa[x]=getfa(fa[x]);}void Tarjan_LCA(int u,int pre){    father[u]=pre; fa[u]=u; deep[u]=deep[pre]+1;    for (int i=Head[u];i;i=edge[i].next)    {        int v=edge[i].v;        if (v==pre) continue;        Tarjan_LCA(v,u);        fa[v]=u;    }    vis[u]=true;    for (int i=Headq[u];i;i=que[i].next)        if (vis[que[i].v]) lca[que[i].id]=getfa(que[i].v);}void dfs(int u,int pre){    ans[u]-=a[T[u]+deep[u]]+b[T[u]-deep[u]+n];    for (int i=Head[u];i;i=edge[i].next)        if (edge[i].v!=pre) dfs(edge[i].v,u);    for (int i=Headup[u];i;i=up[i].next) a[up[i].x]+=up[i].y;    for (int i=Headdown[u];i;i=down[i].next) b[down[i].x+n]+=down[i].y;    ans[u]+=a[T[u]+deep[u]]+b[T[u]-deep[u]+n];}int main(){    scanf("%d%d",&n,&m);tot=0;    for (int i=1;i<n;i++)    {        int x,y;        scanf("%d%d",&x,&y);        adde(x,y); adde(y,x);    }    tot=0;    for (int i=1;i<=n;i++) scanf("%d",&T[i]);    for (int i=1;i<=m;i++)    {        scanf("%d%d",&s[i],&t[i]);        addq(s[i],t[i],i);        addq(t[i],s[i],i);    }    Tarjan_LCA(1,0);    tot=tot1=0;    for (int i=1;i<=m;i++)    {        addup(s[i],deep[s[i]],1);        addup(father[lca[i]],deep[s[i]],-1);        adddown(t[i],deep[s[i]]-2*deep[lca[i]],1);        adddown(lca[i],deep[s[i]]-2*deep[lca[i]],-1);    }    dfs(1,0);    for (int i=1;i<n;i++) printf("%d ",ans[i]);    printf("%d\n",ans[n]);    system("pause");    return 0;}

T3

#include<bits/stdc++.h>using namespace std;const int MAXN=2000+10;int f[MAXN][MAXN],c[MAXN],d[MAXN],n,m,v,e;double k[MAXN],k_[MAXN],s[MAXN][MAXN][2],ans;void init(){    memset(f,0x3f,sizeof(f));    scanf("%d%d%d%d",&n,&m,&v,&e);    memset(s,0x43,sizeof(s));    ans=1e16;    for (int i=1;i<=n;i++) scanf("%d",&c[i]);    for (int i=1;i<=n;i++) scanf("%d",&d[i]);    for (int i=1;i<=n;i++) scanf("%lf",&k[i]),k_[i]=1.0-k[i];    for (int i=1;i<=e;i++)    {        int x,y,z;        scanf("%d%d%d",&x,&y,&z);        if (f[x][y]>z) f[x][y]=f[y][x]=z;    }    for (int i=1;i<=v;i++) f[i][i]=0;    for (int kk=1;kk<=v;kk++)        for (int i=1;i<=v;i++)            for (int j=1;j<=v;j++)                f[i][j]=min(f[i][j],f[i][kk]+f[kk][j]);}int main(){    init();    memset(s[1],0,sizeof(s[1]));    s[1][0][1]=1e16;    if (n==1) ans=0;    for (int i=2;i<=n;i++)        for (int j=0;j<=m;j++)        {            int d1=f[c[i-1]][c[i]],d2=f[c[i-1]][d[i]];            int d3=f[d[i-1]][c[i]],d4=f[d[i-1]][d[i]];            s[i][j][0]=min(s[i-1][j][0]+d1,s[i-1][j][1]+k[i-1]*d3+k_[i-1]*d1);            if (j) s[i][j][1]=min(s[i-1][j-1][0]+k[i]*d2+k_[i]*d1,s[i-1][j-1][1]+                   k_[i-1]*k_[i]*d1+k_[i-1]*k[i]*d2+k[i-1]*k_[i]*d3+k[i-1]*k[i]*d4);            if (i==n) ans=min(ans,min(s[i][j][0],s[i][j][1]));        }    printf("%.2lf\n",ans);    return 0;}
原创粉丝点击