NOIP2016 Day1

来源:互联网 发布:58同城网络销售可靠吗 编辑:程序博客网 时间:2024/06/06 09:13

难度:T1<T3T2
十分鬼畜

T1 玩具谜题

根据朝向和位置的关系模拟即可
O(m)

神奇的Mogician
233

#include<bits/stdc++.h>using namespace std;#define N 100010int a[N];char b[N][11];int main(){    int n,m,i;    scanf("%d%d",&n,&m);    for (i=0;i<n;i++) scanf("%d%s",&a[i],b[i]);    int Las=0;    for (i=1;i<=m;i++){        int x,y;        scanf("%d%d",&x,&y);        y%=n;        if (x==a[Las]){            Las-=y;            if (Las<0) Las+=n;        }else{            Las+=y;            if (Las>=n) Las-=n;        }    }    printf("%s\n",b[Las]);    return 0;}

T2 天天爱跑步

这一题的数据切分完美的引导了走向正解的道路

首先考虑一条链的情况
一个人要么向1走 要么向n
1走的话 第wi秒所在位置为swi
n走的话 第wi秒所在位置为s+wi
分类讨论
swi=i -> i+wi=s 要求ti
s+wi=i -> iwi=s 要求ti
主要是如何判断t的位置
其实就是更新st的区间
那么用vector存储 用差分维护
对于一个点的答案 分别求一下i+wiiwi的位置上有多少数即可

还有s=1 从根向叶子走
直接按dep差分
s+wx=depx -> s=depxwx
那么t=1也类似

再看普通情况 可以把一条路径从lca处劈开
islca的路径上 deps=i+wi
itlca的路径上 dept=i+(diss,twi) -> iwi=deptdiss,t
由于差分也包括lca处 有一个差分处理到lca的父亲节点即可
注意第二种情况可能会减成负数 要处理一下
O(n)(除去求lca的部分)

以前一直听别人说要用LCT 结果发现被忽悠了 并没那么难

#include<bits/stdc++.h>using namespace std;#define N 300010inline void rd(int &x){    char c;x=0;    while (c=getchar(),c<48);    do x=(x<<1)+(x<<3)+(c^48);    while (c=getchar(),c>=48);}inline void pt(int x){    if (!x){putchar('0'); return;}    int s[10],t;    for (t=0;x;x/=10) s[t++]=x%10;    while (t) putchar(s[--t]^48);}struct edge{    int nxt,t;}e[N<<1];int head[N],edge_cnt;void add_edge(int x,int y){    e[edge_cnt]=(edge){head[x],y};    head[x]=edge_cnt++;}int n,m,fa[N],dep[N],siz[N],son[N],top[N],w[N];void Dfs(int x,int f){    fa[x]=f;    dep[x]=dep[f]+1;    siz[x]=1;    int i;    for (i=head[x];~i;i=e[i].nxt){        int to=e[i].t;        if (to==f) continue;        Dfs(to,x);        siz[x]+=siz[to];        if (siz[to]>siz[son[x]]) son[x]=to;    }}void Dfs1(int x,int tp){    top[x]=tp;    if (son[x]) Dfs1(son[x],tp);    int i;    for (i=head[x];~i;i=e[i].nxt){        int to=e[i].t;        if (to==fa[x] || to==son[x]) continue;        Dfs1(to,to);    }}int LCA(int x,int y){    while (top[x]!=top[y]){        if (dep[top[x]]<dep[top[y]]) swap(x,y);        x=fa[top[x]];    }    return dep[x]<dep[y]?x:y;}struct node{    int op,s;};vector<node>P1[N],P2[N];int ans[N],sum1[N],sum2[N<<1];void dfs(int x,int f){    int i;    if (dep[x]+w[x]<=n) ans[x]-=sum1[dep[x]+w[x]];    ans[x]-=sum2[dep[x]-w[x]+N];    for (i=head[x];~i;i=e[i].nxt){        int to=e[i].t;        if (to==f) continue;        dfs(to,x);    }    for (i=0;i<(int)P1[x].size();i++) sum1[P1[x][i].s]+=P1[x][i].op;    for (i=0;i<(int)P2[x].size();i++) sum2[P2[x][i].s]+=P2[x][i].op;    if (dep[x]+w[x]<=n) ans[x]+=sum1[dep[x]+w[x]];    ans[x]+=sum2[dep[x]-w[x]+N];}int main(){    memset(head,-1,sizeof(head));    int i;    rd(n),rd(m);    for (i=1;i<n;i++){        int x,y;        rd(x),rd(y);        add_edge(x,y);        add_edge(y,x);    }    for (i=1;i<=n;i++) rd(w[i]);    Dfs(1,0);    Dfs1(1,1);    for (i=1;i<=m;i++){        int s,t;        rd(s),rd(t);        int c=LCA(s,t);        int d=dep[s]+dep[t]-dep[c]*2;        P1[s].push_back((node){1,dep[s]});        P1[c].push_back((node){-1,dep[s]});        P2[t].push_back((node){1,dep[t]-d+N});        P2[fa[c]].push_back((node){-1,dep[t]-d+N});    }    dfs(1,1);    for (i=1;i<=n;i++) pt(ans[i]),putchar(' ');    return 0;}

T3 换教室

一个比较简单的期望dp题
首先Floyd预处理
dpi,j,k表示前i个时间 申请了jk=1/0代表第i个是否申请 的最小期望代价
由于概率是固定且独立的 每次直接从上一层乘上对应概率转移即可
O(v3+nm)

#include<bits/stdc++.h>using namespace std;#define N 2010#define M 310int dis[M][M],n,m,v,e,a[N][2];double b[N],c[N],dp[N][N][2];void Floyd(){    int i,j,k;    for (k=1;k<=v;k++)        for (i=1;i<=v;i++)            for (j=1;j<=v;j++)                dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);}void DP(){    int i,j;    for (i=1;i<=n;i++)        for (j=0;j<=m;j++)            dp[i][j][0]=dp[i][j][1]=1e9;    dp[1][0][0]=dp[1][1][1]=0;    for (i=2;i<=n;i++){        int t1=a[i-1][0],t2=a[i-1][1],t3=a[i][0],t4=a[i][1];        for (j=0;j<=min(m,i);j++){            dp[i][j][0]=min(dp[i][j][0],dp[i-1][j][0]+dis[t1][t3]);            dp[i][j][0]=min(dp[i][j][0],dp[i-1][j][1]+dis[t1][t3]*c[i-1]+dis[t2][t3]*b[i-1]);            if (j){                dp[i][j][1]=min(dp[i][j][1],dp[i-1][j-1][0]+dis[t1][t3]*c[i]+dis[t1][t4]*b[i]);                dp[i][j][1]=min(dp[i][j][1],dp[i-1][j-1][1]+dis[t1][t3]*c[i-1]*c[i]+dis[t2][t3]*b[i-1]*c[i]+dis[t1][t4]*c[i-1]*b[i]+dis[t2][t4]*b[i-1]*b[i]);            }        }    }}int main(){    int i;    memset(dis,63,sizeof(dis));    scanf("%d%d%d%d",&n,&m,&v,&e);    for (i=1;i<=n;i++) scanf("%d",&a[i][0]);    for (i=1;i<=n;i++) scanf("%d",&a[i][1]);    for (i=1;i<=n;i++) scanf("%lf",&b[i]),c[i]=1-b[i];    for (i=1;i<=e;i++){        int x,y,z;        scanf("%d%d%d",&x,&y,&z);        dis[x][y]=min(dis[x][y],z);        dis[y][x]=min(dis[y][x],z);    }    for (i=1;i<=v;i++) dis[i][i]=0;    Floyd();    DP();    double ans=1e9;    for (i=0;i<=m;i++) ans=min(ans,min(dp[n][i][1],dp[n][i][0]));    printf("%.2f\n",ans);    return 0;}

Date:2017/10/29
By CalvinJin