zoukankan      html  css  js  c++  java
  • NOIp2005 过河【dp+离散化】By cellur925

    题目传送门

    $30pts$

    状态和转移都比较好想:设$f[i]$表示跳到$i$位置,踩到的最小石子数。转移方程也很明了,为$f[i]$=$min${$f[i-j]$),,这个位置有石子时答案再加1,$s<=j<=t$。

    但是出了几次小坑 :首先答案不一定是$f[l]$,因为可能跳过去,但也算到达彼岸了。其次我用的$stone$数组不再代表石子个数,而是下标,所以开到$10000$。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 
     5 using namespace std;
     6 
     7 int l,s,t,m,ans=20000;
     8 int f[20000],stone[20000];
     9 
    10 int main()
    11 {
    12     scanf("%d%d%d%d",&l,&s,&t,&m);
    13     for(int i=1;i<=m;i++)
    14     {
    15         int qwq=0;
    16         scanf("%d",&qwq);
    17         stone[qwq]=1;
    18     }
    19     memset(f,127,sizeof(f));
    20     f[0]=0;
    21     for(int i=0;i<=l;i++)
    22     {
    23         for(int j=s;j<=t;j++)
    24         {
    25             if(i-j<0) break;
    26             f[i]=min(f[i-j],f[i]);
    27         }
    28         if(stone[i]) f[i]++;
    29     }
    30     for(int i=0;i<=t;i++) ans=min(ans,f[l-i]+stone[l]);
    31     printf("%d",ans);
    32     return 0;
    33 }
    30 pts

    $100pts$

    下标太大了呀...达到了丧心病狂的$1e9$。考虑优化,转移貌似没得搞,考虑状态优化。其实注意到这个条件我们首先就应该想到离散化。因为虽然长度很大,但石子个数却很小。也就是说,两个石子间可能会有很长的空隙。

    有两个压缩方法:膜2520和膜72。(一步青蛙最多跳10个单位)2520是1,2,3,4,5,6,7,8,9,10的最小公倍数,因此从一个点出发,无论青蛙能跳多少距离,它一定能到2520。当两个石子间的距离大于2520,我们对其取膜。因为当距离大于2520时,我们一定可以连续跳某次,不经过任何石子。这样我们就成功地进行了离散化。

    同上,最后我们还要枚举跳过(一声)的情况。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #define maxn 1000000
     5 
     6 using namespace std;
     7 
     8 int l,s,t,m,ans=2520;
     9 int stone[maxn],d[maxn],flag[maxn],f[maxn];
    10 
    11 int main()
    12 {
    13     scanf("%d",&l);
    14     scanf("%d%d%d",&s,&t,&m);
    15     for(int i=1;i<=m;i++) scanf("%d",&stone[i]);
    16     sort(stone+1,stone+1+m);
    17     for(int i=1;i<=m;i++) d[i]=(stone[i]-stone[i-1])%2520;
    18     for(int i=1;i<=m;i++)
    19     {
    20         stone[i]=stone[i-1]+d[i];
    21         flag[stone[i]]=1;
    22     }
    23     memset(f,127,sizeof(f));
    24     f[0]=0;
    25     for(int i=1;i<=stone[m]+t;i++)
    26     {
    27         for(int j=s;j<=t;j++)
    28         {
    29             if(i-j<0) break;
    30             f[i]=min(f[i-j],f[i]);
    31         }
    32         if(flag[i]) f[i]++;
    33     }
    34     for(int i=0;i<=t;i++) ans=min(ans,f[i+stone[m]]);
    35     printf("%d",ans);
    36     return 0;
    37 }
    AC
  • 相关阅读:
    「BZOJ1935」[SHOI2007]园丁的烦恼
    【BZOJ3262】陌上花开
    CDQ分治入门
    「luogu2664」树上游戏
    zoj3995 fail树
    zoj3997网络流+数学
    树状数组区间更新区间查询以及gcd的logn性质
    可修改的区间第K大 BZOJ1901 ZOJ2112
    数论容斥比较快速的做法和二分图判定1
    浙工大新生赛莫队处理+区间DP+KMP+分析题
  • 原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9744962.html
Copyright © 2011-2022 走看看