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]−2∗deep[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;
}