洛谷1052 过河

    传送门^o^

只看题目描述 你会发现这是一道非常简单的 dp 题

但是 数据范围是   L109

30分解:

就是很简单的啊

 1 #include
 2 #include
 3 #include
 4 #define go(i,a,b) for(register int i=a;i<=b;i++)
 5 #define yes(i,a,b) for(register int i=a;i>=b;i--)
 6 #define mem(a,b) memset(a,b,sizeof(a));
 7 #define ll long long
 8 #define db double
 9 using namespace std;
10 int read()
11 {
12     int x=0,y=1;char c=getchar();
13     while(c<'0'||c>'9') {if(c=='-') y=-1;c=getchar();}
14     while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
15     return x*y;
16 }
17 int l,s,m,t;
18 ll ans,dp[300000];
19 bool f[300000];
20 int main()
21 {
22     l=read();s=read();t=read();m=read();mem(dp,77);ans=2100000000;
23     go(i,1,m) f[read()]=1;
24     if(!f[0]) dp[0]=0;else dp[0]=1;
25     go(i,1,l+t)
26     {
27         go(j,s,t)
28         {
29             if(i-j<0) continue ;
30             dp[i]=min(dp[i],dp[i-j]+(f[i]==1));
31         }
32         if(i>=l) ans=min(ans,dp[i]);
33     }
34     printf("%lld",ans);
35     return 0;
36 }
30分 View Code

再讲一下我自己想的方法(但是写了好久代码也写不对qwq):

  前面的方法中 for(j,s,t) dp[i]=min(dp[i],dp[i-j]) (如果i处有石头就再+1)

  发现要求dp[i] 只要知道dp[i-t]~dp[i-s] 即可 前面的都对现在没有影响

  s,t<=10 范围非常小就可以不要开之前的dp[]数组了

  又发现只要求 min(dp[i-t]~dp[i-s])

  好像滑动窗口啊!!!

  为了方便还可以用deque和queue

  我觉得我说的好有道理啊  但是我写不对qwq

我看懂的题解

  我们发现不能直接像之前30分的做法那样DP

  是因为L实在是太大了 开不了那么大的数组

  所以我们就想能不能把L变得小一点

洛谷1052 过河_第1张图片

  如图 显然灰色箭头是可以走得到的地方(第i步走的最近和走的最远之间的)

  起初还有灰色箭头覆盖不到的地方

  但是我们可以发现当红色点和蓝色点重合之后 灰色箭头一定可以覆盖到后面的每一个点

  而重合点即为s和t的最小公倍数lcm

  当两块石头之间的间隔大于lcm时 直接把它压缩成lcm

  但是要注意一种特殊的情况 就是当s==t时 特判即可

CODE

 1 #include
 2 #include
 3 #include
 4 #include
 5 #define go(i,a,b) for(register int i=a;i<=b;i++)
 6 #define mem(a,b) memset(a,b,sizeof(a));
 7 #define M 90*100+10
 8 #define N 100+10
 9 using namespace std;
10 int read()
11 {
12     int x=0,y=1;char c=getchar();
13     while(c<'0'||c>'9') {if(c=='-') y=-1;c=getchar();}
14     while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
15     return x*y;
16 }
17 int l,s,m,t,ans,a[N],b[N],dp[M];
18 bool f[M];
19 int main()
20 {
21     l=read();s=read();t=read();m=read();mem(dp,77);dp[0]=0;ans=210;
22     go(i,1,m) a[i]=read();
23     sort(a+1,a+m+1);
24     if(s==t)
25     {
26         ans=0;
27         go(i,1,m) if(!(a[i]%s)) ans++;
28         printf("%d",ans);
29         return 0;
30     }
31     go(i,1,m)
32     {
33         if(a[i]-a[i-1]>s*t) b[i]=b[i-1]+s*t;
34         else b[i]=b[i-1]+a[i]-a[i-1];
35         f[b[i]]=1;
36     }
37     l=b[m]+t*s;
38     go(i,1,l)
39     {
40         go(j,s,t)
41         {
42             if(i-j<0) continue ;
43             dp[i]=min(dp[i],dp[i-j]+(f[i]==1));
44         }
45         if(i>=b[m]) ans=min(ans,dp[i]);
46     }
47     printf("%d",ans);
48     return 0;
49 }
View Code

  至此 洛谷普及训练场所有DP专题都通关啦(当然不是都完成了qwq)

  ^o^ 然后现在要去回顾一下原来写过的DP题

转载于:https://www.cnblogs.com/forward777/p/10335656.html

你可能感兴趣的:(洛谷1052 过河)