1. 程式人生 > 實用技巧 >【ural 1223】 Chernobyl' Eagle on a Roof 題解

【ural 1223】 Chernobyl' Eagle on a Roof 題解

URAL-1223 Chernobyl’ Eagle on a Roof 題解

詳細的題解、dp優化的個人理解和解釋可以見我的這一篇文章

本文僅用於存放AC的程式碼以供參考。

O(k*n^2) 無優化dp

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
#define REG register
#define rep(i,a,b) for(REG int i=a;i<=b;i++)
#define Rep(i,a,b) for(REG int i=a;i>=b;i--)
const int INF=1e9;
int N,K,f[20][1010];
inline int log2(int x){
    int l=1,r=x,c=0;
    while(l<=r){
        int mid=(l+r)>>1; c++;
        if(r-mid>mid-l) l=mid+1;
        else r=mid-1;
    }
    return c;
} 
int main(){
    while(1){
        scanf("%d%d",&K,&N);
        if(K==N&&K==0) break;
        if(K>log2(N)){
            printf("%d\n",log2(N)); continue;
        }
        memset(f,0,sizeof(f));
        rep(i,1,N) f[1][i]=i;
        rep(i,2,K){
            rep(j,1,N){
                f[i][j]=INF;
                rep(w,1,j)
                f[i][j]=min(f[i][j],max(f[i-1][w-1],f[i][j-w])+1);
            }
        }
        printf("%d\n",f[K][N]);
    }
    return 0;
}

O(KNlogN) 二分優化dp

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF=1e9,K=20,N=1010;
inline int log2(int x){
    int l=1,r=x,c=0;
    while(l<=r){
        int mid=(l+r)>>1; c++;
        if(r-mid>mid-l) l=mid+1;
        else r=mid-1;
    }
    return c;
}
int k,n,a[2][N];
int main(){
    while(scanf("%d%d",&k,&n)==2){
        if(k+n==0) break;
        int t=log2(n); 
        if(k>=t){
            printf("%d\n",t);
            continue;
        }
        int *p=a[0],*f=a[1];
        for(int i=1;i<=n;i++) f[i]=i;
        for(int i=2;i<=k;i++){
            swap(p,f);
            for(int j=1;j<=n;j++) f[j]=0;
            f[1]=1;
            for(int j=2;j<=n;j++){
                t=log2(j);
                if(i>=t){ f[j]=t; continue; }
                int l=1,r=j,mid,ans=r;
                while(l<=r){
                    mid=(l+r)>>1;
                    if(p[mid-1]>=f[j-mid]) ans=mid,r=mid-1;
                    else l=mid+1;
                }
                f[j]=max(p[ans-1],f[j-ans])+1;
                if(--ans>=1) f[j]=min(f[j],max(p[ans-1],f[j-ans])+1);
            }
        }
        printf("%d\n",f[n]);
    }
    return 0;
}

O(KN)線性優化

這裡是沒有開long long的必要的,但是我懶得改了。

#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
inline ll log2(ll x){
    ll l=1,r=x,c=0;
    while(l<=r){
        ll mid=(l+r)>>1; c++;
        if(r-mid>mid-l) l=mid+1;
        else r=mid-1;
    }
    return c;
}
vector<ll> f,p; 
int main(){
    while(1){
        ll k,n; scanf("%lld%lld",&k,&n);
        if(k+n==0) break;
        if(k>=log2(n)){ printf("%lld\n",log2(n)); continue; }
        f.resize(n+1); 
        for(ll i=1;i<=n;i++) f[i]=i;
        for(ll i=2;i<=k;i++){
            f.swap(p); f.resize(n+1);
            ll pre=0; f[1]=1;
            for(ll j=2;j<=n;j++){
                if(max(f[pre],p[j-pre-1])+1==f[j-1]) f[j]=f[j-1];
                else f[j]=f[j-1]+1,pre=j-1;
            }
        }
        printf("%lld\n",f[n]);
    }
    return 0;
}

可以過1e18大資料的演算法

#include <cstdio>
#include <cmath>
using namespace std;
typedef long long ll;
#define REG register
#define rep(i,a,b) for(REG int i=a;i<=b;i++)
#define Rep(i,a,b) for(REG int i=a;i>=b;i--)
inline char getc(){
    static char buf[1<<14],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<14,stdin),p1==p2)?EOF:*p1++;
}
inline ll scan(){
    REG ll x=0; REG char ch=0;
    while(ch<48) ch=getc();
    while(ch>=48) x=x*10+ch-48,ch=getc();
    return x;
}
inline ll log2(ll x){
    ll l=1,r=x,mid,c=0;
    while(l<=r){
        mid=(l+r)>>1; c++;
        if(mid-l>r-mid) r=mid-1;
        else l=mid+1;
    }
    return c;
}
const ll F=2e6,K=60,N=1e18;
ll f[K+1][F],end[K+1];
inline void prework(){
    rep(i,1,F-200) f[1][i]=i;
    rep(i,1,F-200){
        rep(j,2,K){
            if(end[j]) break;
            f[j][i]=f[j][i-1]+f[j-1][i-1]+1;
            if(f[j][i]>=N) end[j]=i;
        }
    } 
}
int main(){
    //REG int T=scan();
    prework();
    while(1){
        REG ll k=scan(),n=scan(),temp;
        if(n+k==0) break;
        if(k==1){ printf("%lld\n",n); continue; }
        if(k==2){
            ll t=floor(sqrt(n<<1));
            if(t*(t+1)<n<<1) t++;
            printf("%lld\n",t); continue;
        }
        temp=log2(n);
        if(k>=temp){ printf("%lld\n",temp); continue; }
        REG int l=1,r=end[k],mid,ans;
        while(l<=r){
            mid=(l+r)>>1;
            if(f[k][mid]>=n) r=mid-1,ans=mid;
            else l=mid+1;
        }
        printf("%d\n",ans);
    }
    return 0;
}