NOIP2016提高组DAY1题解

T1:玩具谜题

考察知识:模拟

算法难度:X+ 实现难度:X+

分析:

把题目读懂之后就比较简单了,直接按题目说明模拟即可

为了简洁,我们用 0...n-1 表示每个小人的位置就可以了

代码:

#include<cstdio>
int n,m,f[100005];//f表示朝向
char name[100005][12];
int main(){
    int f_,k;//f_:表示左右
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++) scanf("%d%s",f+i,name[i]);
    int pos=0;
    while(m--){
        scanf("%d%d",&f_,&k);
        if(f_^f[pos]) pos=(pos+k)%n;//用异或比较简洁
        else pos=(pos+n-k)%n;
    }
    printf("%s",name[pos]);
    return 0;
}

T2:天天爱跑步

考察知识:LCA,差分,树链剖分

算法难度:XXXX+ 实现难度:XXXX+

分析:这一定是NOIP有史以来最难的DAY1T2了,甚至比T3还要难。

我不准备介绍我的方法,因为我的方法太长,代码量比较大,思路也比较难表述,所以建议大家参考:P1600题解

T3:换教室

考察知识:动态规划,期望

算法难度:XXXX 实现难度:XXX+

分析:这应该是NOIP首次考期望,所以难度主要在算法知识上,如果你不知道期望的基本知识,那基本上没戏了。

对于这道题,我们需要用动态规划解决:

定义状态方程:f(i,j,k)表示前 i 次课中申请 j 次,需要消耗的最小体力值,其中 k 为 0 时表示第 i 次课没有申请,k为 1 表示第 i 次课申请了。

边界:f(1,0,0)=f(1,1,1)=0

状态转移方程:

其中:x,y,x',y' 分别表示题目中的 c[i-1],c[i],d[i-1],d[i]d(x,y)表示教室 x,y 之间的距离

f(i,0,0)=f(i-1,0,0)+d(x,y)

说明:这个很好推,不解释

f(i,j,0)=min \left\{\begin{matrix} f(i-1,j,0)+d(x,y) \cdots \cdots \cdots \cdots \cdots \cdots \cdots \cdots \cdots A& & \\ f(i-1,j,1)+(1-k_i) \times d(x,y)+k_i \times d(x',y) \cdots B& & \end{matrix}\right.

说明:对于A 比较好推,对于B:由于第 i-1 节课申请了,所以有 1-k_i 的概率不成功,k_i 概率成功,由期望的概念,我们加权求和就可以了

f(i,j,1)=min \left\{\begin{matrix} f(i-1,j-1,0)+(1-k_i)\times d(x,y) +k_i*d(x,y') & \\ f(i-1,j-1,1)+(1-k_{i-1})(1-k_i)\times d(x,y)+(1-k_{i-1})\times k_i \times d(x,y')+k_{i-1}\times (1-k_i)\times d(x',y)+k_{i-1}k_i\timesd(x',y')& \end{matrix}\right.

说明:同理,但是要注意要考虑第 i-1节和 i 节同时申请了的情况,有 4 种情况

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=2005;
int n,m,v,E,a[maxn],b[maxn],d[305][305];
double k[maxn];
double f[maxn][maxn][2];
void solve(){
    double ans=20182018.2018;
    for(int i=0;i<=n;i++)
      for(int j=0;j<=m;j++)
        f[i][j][0]=f[i][j][1]=20182018.2018;
    f[1][0][0]=f[1][1][1]=0.0;
    for(int i=2;i<=n;i++){
        int x=a[i-1],y=a[i],x_=b[i-1],y_=b[i];
        f[i][0][0]=f[i-1][0][0]+(double)d[x][y];
        double  d1=(double)d[x][y],
                d2=(1-k[i-1])*d[x][y]+d[x_][y]*k[i-1],
                d3=k[i]*d[x][y_]+(1-k[i])*d[x][y],
                d4=k[i]*k[i-1]*d[x_][y_]+(1-k[i-1])*k[i]*d[x][y_]+k[i-1]*(1-k[i])*d[x_][y]+(1-k[i-1])*(1-k[i])*d[x][y];
        for(int j=1;j<=min(i,m);j++){
            f[i][j][0]=min(f[i-1][j][0]+d1,f[i-1][j][1]+d2);
            f[i][j][1]=min(f[i-1][j-1][0]+d3,f[i-1][j-1][1]+d4);
        }
    }
    for(int i=0;i<=m;i++) ans=min(ans,min(f[n][i][0],f[n][i][1]));
    printf("%.2lf\n",ans);
}
void build(){
    int u,v_,l;//防止变量重名 
    memset(d,0x1f,sizeof(d));
    scanf("%d%d%d%d",&n,&m,&v,&E);
    for(int i=1;i<=n;i++) scanf("%d",a+i);
    for(int i=1;i<=n;i++) scanf("%d",b+i);
    for(int i=1;i<=n;i++) scanf("%lf",k+i);
    for(int i=1;i<=v;i++) d[i][i]=0;
    for(int i=1;i<=E;i++){
        scanf("%d%d%d",&u,&v_,&l);
        d[u][v_]=d[v_][u]=min(d[u][v_],l);
    }	
    for(int K=1;K<=v;K++)//floyd
      for(int i=1;i<=v;i++)
        for(int j=1;j<=v;j++)
          d[i][j]=min(d[i][j],d[i][K]+d[K][j]);
}
int main(){
    build();
    solve();
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值