zoukankan      html  css  js  c++  java
  • 过河

    题目传送门

    递推式很容易想得到  f[i]=min(f[i-j]+当前点是否有石头,f[i])

    直接DP +一些特判估计能骗50%吧。题目开的100%数据L为10^9,那以这样的转移方程肯定爆炸。

    但是最后看了下题解发现还是用这个转移式,只不过要路径压缩(本蒟蒻不会,看了下题解里Panda_hu 大佬 终于懂了)

    只要把相隔大于90的石头做一下路径压缩就行了,之后把总长度修改一下就OK了

    为什么可以这样呢?

        当S!=T时,任意步数p,p+1,肯定互质。。。然后gcd(p,p+1)=1,那么大于p*(p+1)的点在后面肯定也跑得了。那么就有下面代码。

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <string>
    #include <cstdlib>
    #include <sstream>
    #include <iostream>
    #include <queue>
    #include <stack>
    #include <set>
    #include <map>
    #include <algorithm>
    #include <functional>
    using namespace std;
    #define ll long long
    #define re register
    #define fi first
    #define se second
    #define mp make_pair
    #define pb push_back
    #define P pair<int,int>
    void read(int &a)
    {
        a=0;
        int d=1;
        char ch;
        while(ch=getchar(),ch>'9'||ch<'0')
            if(ch=='-')
                d=-1;
        a=ch-'0';
        while(ch=getchar(),ch>='0'&&ch<='9')
            a=a*10+ch-'0';
        a*=d;
    }
    void write(int x)
    {
        if(x<0)
            putchar(45),x=-x;
        if(x>9)
            write(x/10);
        putchar(x%10+'0');
    }
    int f[10005],a[10005],b[10005],c[10005];///f[i]为在i位置踩石头最小的数
    bool book[10005];
    int main()
    {
        int L;
        read(L);
        int S,T,M;
        read(S);
        read(T);
        read(M);
        if(S==T)
        {
            int ans=0;
            for(re int i=1;i<=M;i++)
            {
                int x;
                read(x);
                if(x%S==0)
                    ans++;
            }
            return write(ans),0;
        }
        for(re int i=1;i<=M;i++)
            read(a[i]);
        sort(a+1,a+M+1);///不排序会RE!!!
        memset(f,0x3f,sizeof(f));
        a[0]=0,f[0]=0;
        c[M+1]=min(L-a[M],91);///最后一个石头与终点的最短距离,压缩
        L=0;
        for(re int i=1;i<=M;i++)///压缩路径
            b[i]=min(a[i]-a[i-1],90),L+=b[i],book[L]=1;
        L+=c[M+1];
        for(re int i=S;i<=L+10;i++)///从S开始的原因是因为i<S时都跳过去了,f[i]肯定为0
            for(re int j=S;j<=T;j++)
                f[i]=min(f[i],f[i-j]+(book[i]==1));///当前点与上一级跳过来的点+1做转移,这个转移方程应该很简单。
        int ans=0x3fffffff;
        for(re int i=L;i<=L+10;i++)
            ans=min(f[i],ans);
        write(ans);
        return 0;
    }
    View Code
  • 相关阅读:
    高斯消去法
    【转】sscanf和sprintf是scanf和printf家族的一对成员
    ps电信
    XNA准备篇(一)
    超级BT的SQL2008 在WIN7下附加 SQL2005的数据库
    绘制半口角
    动态的在输入框边上显示可输入的剩余字符数
    CallContext vs. ThreadStatic vs. HttpContext[待翻译]
    Vista 系统下安装 GhostDoc for Visual Studio 2008
    非常优秀的开源框架地址
  • 原文地址:https://www.cnblogs.com/acm1ruoji/p/10685990.html
Copyright © 2011-2022 走看看