洛谷 P1052过河

这个是题干:https://www.luogu.org/problemnew/show/P1052#sub

这是一道NOIP2005年的提高组的题,那道题一看,就是要用动态规划,状态转移方程也十分简单。只需要考虑是从哪个地方来的,看看即将到达的点是否有石子。用一维数组 f[x] 表示第X位的步数(额,这只是30分的写法,L 的取值太大,数组承受不了)

之后,我又想骗一点分,就特判了一下s==t的情况,结果竟然又过了一个点,简直就是玄学。。。

#include<iostream>
#include<cstring>
using namespace std;
const int maxN=20000100;
int l,s,t,m,ans,f[maxN],b[110];
bool a[maxN];

void prepare()
{ 
    memset(f,-1,sizeof(f));
    f[0]=0;
    for(int i=s;i<=l+t-1;++i){
        for(int j=s;j<=min(t,i);++j){
            if(f[i-j]==-1)
                continue;
            if(f[i]==-1||f[i-j]+a[i]<f[i])
                f[i]=f[i-j]+a[i];   
        }
    }
}

void work()
{
    f[0]=0;
    for(int i=1;i<=m;++i){
        if(b[i]%s==0)
            ans++;
    }
}

int main()
{
    cin>>l>>s>>t>>m;
    for(int i=1;i<=m;++i)
        cin>>b[i];
    if(s==t){
        work();
        cout<<ans<<endl;
        return 0;
    }
    for(int i=1;i<=m;++i)
        a[b[i]]=true;
    prepare();
    int ans=maxN;
    for(int i=l;i<=l+t-1;++i){
        if(f[i]!=-1){
            ans=min(ans,f[i]);
        }
    }
    cout<<ans<<endl;
    return 0;
}

在这里,需要用到一个神奇的的定理,也就是小凯的烦恼(2017年提高组第一题)需要用到的。定理描述如下


有两个互质的自然数p,q,不能用p*x+q*y表示的最大整数是
p*q+-p-q(x,y均为正整数)

有兴趣的可以证明一下~~~

言归正传,如果两个石子相离很远,那么他们之间都可以随意走动,步数不增加,走100000步没用的其实和走100步没用的效果是一样的(都是没用。。)
所以当两块石子的距离超过了没用距离(即(t-1)*t)时,直接将两石子的距离缩短为这个值(但是经本蒟蒻的深思熟虑,发现还是有风险有特例的(或者自己考虑不周,如果有大犇可以解释,请留言教一下本蒟蒻,谢谢!!!))

最后附上代码:

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<utility>
using namespace std;
const int maxN=100000;
int l,s,t,m,ans,st,f[maxN],b[maxN];
bool a[maxN];

void qsort(int l,int r)
{
    if(l>=r)
        return;
    int t=b[rand()%(r-l+1)+l];
    int i=l,j=r;
    while(i<=j){
        while(b[i]<t)i++;
        while(b[j]>t)j--;
        if(i<=j){
            swap(b[i],b[j]);
            i++;
            j--;
        }
    }
    qsort(l,j);
    qsort(i,r);
}

void prepare()
{ 
    memset(f,-1,sizeof(f));
    f[0]=0;
    for(int i=s;i<=st+t-1;++i){
        for(int j=s;j<=min(t,i);++j){
            if(f[i-j]==-1)
                continue;
            if(f[i]==-1||f[i-j]+a[i]<f[i])
                f[i]=f[i-j]+a[i];   
        }
    }
}

void work()
{
    f[0]=0;
    for(int i=1;i<=m;++i){
        if(b[i]%s==0)
            ans++;
    }
}

int main()
{
    cin>>l>>s>>t>>m;
    for(int i=1;i<=m;++i)
        cin>>b[i];
    srand(100000);
    qsort(1,m);
    if(s==t){
        work();
        cout<<ans<<endl;
        return 0;
    }
    b[m+1]=l;
    int add=(t-1)*t;
    for(int i=1;i<=m+1;++i){
        if((b[i]-b[i-1])>add){
            st+=add;
            a[st]=true;
        }
        else{
            st+=(b[i]-b[i-1]);
            a[st]=true;
        }
    }
    prepare();
    int ans=maxN;
    for(int i=st;i<=st+t-1;++i)
        if(f[i]!=-1)
            ans=min(ans,f[i]);
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ljp946/article/details/81218949