【DP50题】day1

P1336 最佳课题选择

范围:1e2的级别->\(O(n^3)\)的算法

集合:考虑物尽其用,给了m个课题就一个一个课题的去更新,记录前i个课题完成了j篇论文的最小时间。那么转移就可以根据m的阶段来划分,从m的上一个阶段递推。

转移:这道题的转移方程挺容易想的:f[i][j]=min(f[i][j],f[i−1][j−k]+a[i]∗k^b[i])

终态f[m][n]

初始化:根据注意到i-1可能为0,那转移就从这里开始。

const int N=210;
int f[N][N];
int n,m;
int a[N],b[N];

inline int ksm(int a,int k){
    int res=1;
    for(;k;k>>=1){
        if(k&1)res=res*a;
        a=a*a;
    }
    return res;
}

#undef int
int main(){
#define int long long
    #ifdef WIN32
    freopen("c.txt","r",stdin);
    #endif
    rd(n),rd(m);//n:论文数,m:课题数
    rep(i,1,m)rd(a[i]),rd(b[i]);
    rep(i,1,n)f[0][i]=INT_MAX;
    rep(i,1,m)
        rep(j,1,n){
            f[i][j]=INT_MAX;
            rep(k,0,j)
                f[i][j]=min(f[i][j],f[i-1][j-k]+a[i]*ksm(k,b[i]));
        }
    printf("%lld\n",f[m][n]);
    return 0; 
}

P1474 货币系统 Money Systems

==完全背包求方案数==

不限制每种货币取的个数,则需要使用完全背包,这里是统计方案数,根据加法原理(分步相加)得出转移方程:f[j]=f[j-a[i]].

记得初始化f[0]=1;


P1233 木棍加工

思想:==归约:==按照第一个关键字从大到小排序后就只用考虑另一个关键字的降序问题;

SOL:

​ 要求的是第二个关键字的最长下降子序列的最小个数,根据导弹拦截第二问用到的定理Dilworth定理:==最少的下降序列个数就等于整个序列最长上升子序列的长度==,求一遍LIS,因为n<=5e3,我就没用nlogn,\(n^2\)跑一边就好了

const int N=5e3+10;
struct qujian{
    int a,b;
    bool operator <(const qujian &rhs)const{
        if(a!=rhs.a)return a>rhs.a;
        return b>rhs.b;
    }
}mg[N];

int f[N],maxx,n;

#undef int
int main(){
#define int long long
    #ifdef WIN32
    freopen("c.txt","r",stdin);
    #endif
    rd(n);
    rep(i,1,n){
        rd(mg[i].a),rd(mg[i].b);
    }
    sort(mg+1,mg+n+1);
    rep(i,1,n){
        f[i]=1;
        rep(j,1,i-1)
            if(mg[j].b<mg[i].b)
                f[i]=max(f[i],f[j]+1);
        maxx=max(maxx,f[i]);
    }
    printf("%lld\n",maxx);
    return 0;
}

好吧,还是悄咪咪复习一下O(nlogn)的做法

    f[++len]=mg[1].b;
    rep(i,2,n){
        if(mg[i].b>f[len])f[++len]=mg[i].b;
        else{
            int p=lower_bound(f+1,f+len+1,mg[i].b)-f;//求按第二关键字的LIS
            f[p]=mg[i].b;
        }
    }
    printf("%lld\n",len);

P2904 USACO08MAR跨河River Crossing

【前置技能】:==语文足够好==

【独立思考+1A】

设f[i]表示1~i只牛全部运输过去的最小花费

预处理sum[i]:运i只牛的总花费

转移方程:f[i]=min(f[i],f[i-j]+sum[j]+M)//加M只因为FJ还要回到对岸

记得最后答案再减去一个M,因为最后一次到对岸的时候FJ已经不用再去接Bessie们了

const int N=2510;
int m[N],sum[N],f[N];
int n,M,cnt;

int main(){
    #ifdef WIN32
    freopen("c.txt","r",stdin);
    #endif
    rd(n),rd(M);
    sum[0]=M;
    rep(i,1,n){
        rd(m[i]);
        sum[i]=sum[i-1]+m[i];
    }
    mem(f,0x3f);
    f[0]=0;
    rep(i,1,n){
        rep(j,1,i){
            f[i]=min(f[i],f[i-j]+sum[j]+M);
        }
    }
    printf("%d",f[n]-M);
    return 0;
}
上一篇:2019 年 10 月训练赛(10.30早)


下一篇:luogu 十一 基本套路 day1