dp1

dp1

Max Sum Plus Plus

Problem - 1024 (hdu.edu.cn)

思路:

转移态方程$dp[i][j]=max(dp[i][j-1],dp[i][j-1]+a[j],dp[i-1][k]+a[j])$表示前j个数中恰好选i组的数的最大和。
意义依次为不取第j个数, 取第j个数归入当前组, 取第j个数归入新的组。同时改题还要用滚动数组优化一下。可以发现$dp[i-1][k]$就是上一组之前的最大dp,用一个数组存一下就可以了。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <map>
#include <vector>
using namespace std;
const int maxn = 1e6+10;
int a[maxn];
int b[maxn];
int dp[maxn];
int main()
{
    int m,n;
    while(scanf("%d%d",&m,&n)!=EOF)
    {
        memset(dp,0,sizeof dp);
        memset(b,0,sizeof b);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        int tep;
        int ans=0;
        for(int i=1;i<=m;i++)
        {
            tep=-1e9;
            for(int j=i;j<=n;j++)
            {
                dp[j]=max(dp[j-1],b[j-1])+a[j];
                b[j-1]=tep;
                tep=max(tep,dp[j]);
            }
        }
        printf("%d\n",tep);
    }
    return 0;
}

Ignatius and the Princess IV

Problem - 1029 (hdu.edu.cn)

思路:???不知道这道题和dp有什么关系,但是出现在题单里。map存一下每个数出现次数即可。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <map>
#include <vector>
#include <unordered_map>
using namespace std;
const int maxn = 1e6+10;
int a[maxn];
int b[maxn];
int dp[maxn];
unordered_map <int ,int > ma;
int main()
{
    int m,n;
    while(scanf("%d",&n)!=EOF)
    {
        ma.clear();
        int ans;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            ma[a[i]]++;
            if(ma[a[i]]==(n+1)/2)
            {
                ans=a[i];
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

Monkey and Banana

Problem - 1069 (hdu.edu.cn)

思路:

状态转移方程$dp[i]=max(dp[j]+a[i].z,dp[i])$
表示以第j块砖为基础时,能搭建的最高高度。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <map>
#include <vector>
#include <unordered_map>
using namespace std;
const int maxn = 1e6+10;
struct node{
    int x,y,z;
};
bool cmp(node a,node b)
{
    if(a.x==b.x) return a.y<b.y;
    return a.x<b.x;
}
node a[maxn];
int n;
int dp[maxn];
int main()
{
    int t=0;
    while(~scanf("%d",&n),n)
    {
        int cnt=0;
        for(int i=1;i<=n;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            a[++cnt]={x,y,z};a[++cnt]={x,z,y};
            a[++cnt]={y,x,z};a[++cnt]={y,z,x};
            a[++cnt]={z,y,x};a[++cnt]={z,x,y};
        }
        sort(a+1,a+1+cnt,cmp);
        int x,y;
        int ans=0;
        for(int i=1;i<=cnt;i++)
        {
            x=a[i].x;
            y=a[i].y;
            dp[i]=a[i].z;
            for(int j=i-1;j>=1;j--)
            {
                if(a[j].x<x&&a[j].y<y)
                {
                    dp[i]=max(dp[i],dp[j]+a[i].z);
                    ans=max(ans,dp[i]);
                }
            }
        }
        printf("Case %d: maximum height = %d\n",++t,ans);  
    }
}

Doing Homework

Problem - 1074 (hdu.edu.cn)

思路:

看到n<=15猜测是状压dp,同时要记录一下状态转移的过程,因为要输出字典序最小,需要倒着遍历。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <map>
#include <vector>
#include <unordered_map>
#include <stack>
using namespace std;
const int maxn = 16;
const int inf = 0x3f3f3f3f;
struct node{
    string s;
    int d,c;
};
bool cmp(node a,node b)
{
    if(a.d==b.d) return a.c<b.c;
    return a.d<b.d;
}
struct node1{
    int fa,now,time,score;
};
int n;
node a[maxn];
node1 dp[1<<15];
vector <string > g;
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        g.clear();
        memset(dp,0,sizeof dp);
        cin>>n;
        for(int i=0;i<n;i++)
        {
            string s;
            int d,c;
            cin>>s>>d>>c;
            a[i]={s,d,c};
        }
        for(int i=1;i<(1<<n);i++)
        {
            dp[i].score=inf;
            for(int j=n-1;j>=0;j--)
            {
                int temp=1<<j;
                if(temp&i)
                {
                    int tem = i-temp;
                    int tt=dp[tem].time+a[j].c-a[j].d;
                    if(tt<0) tt=0;
                    if(tt+dp[tem].score<dp[i].score)
                    {
                        dp[i]={tem,j,dp[tem].time+a[j].c,(tt+dp[tem].score)};
                    }
                }
            }
        }

        cout<<dp[(1<<n)-1].score<<endl;
        stack <int > st;
        int p=(1<<n)-1;
        while(dp[p].time)
        {
            st.push(dp[p].now);
            p=dp[p].fa;
        }
        while(!st.empty())
        {
            int id=st.top();
            st.pop();
            cout<<a[id].s<<endl;
        }
    }
}

Super Jumping! Jumping! Jumping!

Problem - 1087 (hdu.edu.cn)

思路:

和上面的第三题很像,转移态方程$dp[i]=max(dp[i],a[j]+dp[j])$ $a[i]>a[j]$表示前i个并包括第i个的最大递增子序列和。用两层for循环遍历一遍

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <vector>
#include <cstring>
#include <string>
#include <vector>
#include <map>
using namespace std;
const int maxn = 1e4+10;
int a[maxn];
int dp[maxn];
int main()
{
    int n;
    while(~scanf("%d",&n),n)
    {
        memset(dp,0,sizeof dp);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=i;j++)
            {
                if(a[i]>a[j])
                    dp[i]=max(dp[i],dp[j]+a[i]);
            }
            dp[i]=max(dp[i],a[i]);
            ans=max(ans,dp[i]);
        }
        cout<<ans<<endl;
    }
}

Piggy-Bank

Problem - 1114 (hdu.edu.cn)

思路:

简单完全背包问题(注意输出后面有个点)

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <unordered_map>
using namespace std;
const int maxn = 1e5+10;
struct coin{
    int p,w;
}a[maxn];
int dp[maxn];
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        int ans=0;
        memset(dp,0x3f,sizeof dp);
        dp[0]=0;
        int w1,w2;
        cin>>w1>>w2;
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i].p>>a[i].w;
        }
        int w=w2-w1;
        for(int i=1;i<=n;i++)
        {
            for(int j=a[i].w;j<=w;j++)
            {
                dp[j]=min(dp[j],dp[j-a[i].w]+a[i].p);
            }
        }
        if(dp[w]==0x3f3f3f3f) cout<<"This is impossible."<<endl;
        else cout<<"The minimum amount of money in the piggy-bank is "<<dp[w]<<"."<<endl;
    }
}

免费馅饼

Problem - 1176 (hdu.edu.cn)

思路:

定义$dp[i][j]$表示第i秒第j个位置可以接到最大数量的馅饼。转移态方程很容易想到$dp[i][j]=max(dp[i][j],max({dp[i-1][j-1],dp[i-1][j],dp[i-1][j+1]})+mp[j][i])$因为要么就是当前位置转移,要么就是距离为1的位置转移。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn=1e5+10;
const int INF=0x3f3f3f3f;
int mp[15][maxn];
int dp[maxn][15];
int main(void)
{
	int N;
	while(cin>>N)
	{
		memset(mp,0,sizeof(mp));
		if(!N)break;
		int T=0;
		for(int i=0;i<N;i++)
		{
			int x,y;
			scanf("%d %d",&x,&y);
			mp[x+1][y]++;
			T=max(T,y);
		}
		memset(dp,-INF,sizeof(dp));
		dp[0][6]=0;
		for(int i=1;i<=T;i++)
		{
			for(int j=1;j<=11;j++)
				dp[i][j]=max(dp[i][j],max({dp[i-1][j-1],dp[i-1][j],dp[i-1][j+1]})+mp[j][i]);
		}
		int ans=0;
		for(int i=1;i<=11;i++)ans=max(ans,dp[T][i]);
		cout<<ans<<endl;
	}
	return 0;
}

Tickets

Problem - 1260 (hdu.edu.cn)

思路:

定义$dp[i]$表示前i个人所需的最小时间,转移态方程为$dp[i]=min(dp[i-1]+a[i],dp[i-2]+b[i])$因为当前转态要么就是第i-1个人加上第i个人的票价a[i],要么就是第i-2个人加上第i-1和第i个人共同的票价b[i]

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
using namespace std;
const int maxn = 2010;
int dp[maxn];
int a[maxn];
int b[maxn];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(dp,0,sizeof dp);
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        for(int i=2;i<=n;i++)
        {
            scanf("%d",&b[i]);
        }
        dp[1]=a[1];
        dp[2]=min(a[2]+a[1],b[2]);
        for(int i=3;i<=n;i++)
        {
            dp[i]=min(dp[i-1]+a[i],dp[i-2]+b[i]);
        }
        int h=dp[n]/3600+8;
        int m=dp[n]%3600/60;
        int s=dp[n]%60;
        if(h>12)
            printf("%02d:%02d:%02d pm\n", h-12, m, s);
        else
            printf("%02d:%02d:%02d am\n", h, m, s);
    }
    return 0;
}

最少拦截系统

Problem - 1257 (hdu.edu.cn)

思路:

lis模板题了$dp[j]=max(dp[i]+1,dp[j])$

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
using namespace std;
const int maxn = 30010;
int dp[maxn];
int a[maxn];
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        // memset(dp,0,sizeof dp);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            dp[i]=1;
        }
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=i+1;j<=n;j++)
            {
                if(a[j]>a[i])
                    dp[j]=max(dp[i]+1,dp[j]);
            }
            ans=max(dp[i],ans);
        }
        printf("%d\n",ans);
    }
}

FatMouse's Speed

Problem - 1160 (hdu.edu.cn)

思路:

lis变形,多了一层维度但解题思路类似,转移态方程也相同,题目要求输出方案则记录一下路径。

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <stack>
using namespace std;
const int maxn = 1e5+10;
struct node{
    int w,v,id;
}a[maxn];
bool cmp(node a,node b)
{
    if(a.w==b.w) return a.v>b.v;
    return a.w<b.w;
}
int dp[maxn];
int fa[maxn];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n=0;
    int w,v;
    while(scanf("%d %d",&w,&v)!=EOF)
    {
        a[++n]={w,v,n};
        dp[n]=1;
    }
    sort(a+1,a+1+n,cmp);
    int ans=0;
    int id=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            if(a[j].w>a[i].w&&a[j].v<a[i].v)
            {
                if(dp[j]<dp[i]+1)
                {
                    dp[j]=dp[i]+1;
                    fa[j]=i;
                }
            }
        }
        if(dp[i]>ans)
        {
            ans=dp[i];
            id=i;
        }
    }
    cout<<ans<<endl;
    stack <int > st;
    while(fa[id])
    {
        st.push(id);
        id=fa[id];
    }
    st.push(id);
    while(st.size())
    {
        int id=st.top();
        st.pop();
        cout<<a[id].id<<endl;
    }
}

Jury Compromise

1015 -- Jury Compromise (poj.org)

思路:

类似装化为背包问题,没搞得很懂,先放着。

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <queue>
#include <cstring>
#include <string>
#include <vector>
using namespace std;
typedef long long ll;
typedef pair <int ,int > pii;
const int maxn = 440;
pii a[maxn];
int n,m;
int tot;
int dp[30][maxn*2];
int path[30][maxn*2];
struct edge{
    int to,next;
}edge[4*440*210];
void add(int a1,int a2,int b)
{
    edge[++tot].to=b;
    edge[tot].next=path[a1][a2];
    path[a1][a2]=tot;
}
void print(int now)
{
    if(!now) return ;
    print(edge[now].next);
    printf(" %d",edge[now].to);
}
int main()
{
    int cnt=0;
    while(~scanf("%d%d",&n,&m))
    {
        cnt++;
        if(n==0&&m==0) break;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&a[i].first,&a[i].second);
        }
        memset(dp,-0x3f,sizeof dp);
        memset(path,0,sizeof path);
        dp[0][maxn]=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=m;j>=1;j--)
            {
                for(int k=-400;k<=400;k++)
                {
                    if(dp[j-1][k-(a[i].first-a[i].second)+maxn]<0) continue;
                    if(dp[j-1][k-(a[i].first-a[i].second)+maxn]+a[i].first+a[i].second>dp[j][k+maxn])
                    {
                        dp[j][k+maxn]=dp[j-1][k-(a[i].first-a[i].second)+maxn]+a[i].first+a[i].second;
                        path[j][k+maxn]=path[j-1][k-(a[i].first-a[i].second)+maxn];
                        add(j,k+maxn,i);
                    }
                }
            }
        }
        int ans=0,id=0,pp=0,dd=0;
        for(int i=0;i<=400;i++)
        {
            ans=dp[m][i+maxn];id=i;
            if(dp[m][maxn-i]>ans) ans=dp[m][maxn-i],id=-i;
            if(ans>=0) break;
        }
        pp=(ans+id)/2;dd=(ans-id)/2;
        printf("Jury #%d\n",cnt);
        printf("Best jury has value %d for prosecution and value %d for defence:\n",pp,dd);
        print(path[m][id+maxn]);
        printf("\n\n");
    }
}

Common Subsequence

1458 -- Common Subsequence (poj.org)

思路:

这题也是偏模板,用两个指针分别指向两个字符串,当指向的字符相同时,$dp[i][j]=dp[i-1][j-1]+1$,否则$dp[i][j]=max(dp[i][j-1],dp[i-1][j])$

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
using namespace std;
const int maxn = 510;
int dp[maxn][maxn];
int main()
{
    string s1,s2;
    while(cin>>s1>>s2)
    {
        memset(dp,0,sizeof dp);
        for(int i=1;i<=s1.size();i++)
        {
            for(int j=1;j<=s2.size();j++)
            {
                if(s1[i-1]==s2[j-1])
                    dp[i][j]=dp[i-1][j-1]+1;
                else
                    dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
            }
        }
        cout<<dp[s1.size()][s2.size()]<<endl;
    }
}

Help Jimmy

1661 -- Help Jimmy (poj.org)

思路:

题目意思好懂,可能代码写起来麻烦一点,就是开个二维$dp[20000][2]$第二维表示第i块砖左边或右边到地面的距离。转移态方程以左边为例$dp[i][0]=a[i].h-a[k].h+min(dp[k][0]+a[i].x1-a[k].x1,dp[k][1]+a[k].x2-a[i].x1)$注意状态转移的条件就行。

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
using namespace std;
const int maxn = 2e4+10;
const int inf = 0x3f3f3f;
struct node{
    int x1,x2,h;
}a[maxn];
int n,x,y,m;
bool cmp(node a,node b)
{
    return a.h>b.h;
}
int dp[maxn][2];
void left(int i)
{
    int k=i+1;
    while(k<n+1&&a[i].h-a[k].h<=m)
    {
        if(a[i].x1>=a[k].x1&&a[i].x1<=a[k].x2)
        {
            dp[i][0]=a[i].h-a[k].h+min(dp[k][0]+a[i].x1-a[k].x1,dp[k][1]+a[k].x2-a[i].x1);
            return ;
        }
        k++;
    }
    if(a[i].h-a[k].h>m)
        dp[i][0]=inf;
    else
        dp[i][0]=a[i].h;
    return ;
}
void right(int i)
{
    int k=i+1;
    while(k<n+1&&a[i].h-a[k].h<=m)
    {
       if(a[i].x2>=a[k].x1&&a[i].x2<=a[k].x2)
       {
            dp[i][1]=a[i].h-a[k].h+min(dp[k][0]+a[i].x2-a[k].x1,dp[k][1]+a[k].x2-a[i].x2);
            return;
       }
        k++;
    }
    if(a[i].h-a[k].h>m)
        dp[i][1]=inf;
    else
        dp[i][1]=a[i].h;
    return ;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        memset(dp,0,sizeof dp);
        cin>>n>>x>>y>>m;
        a[0].x1=-20000;a[0].x2=20000;a[0].h=0;
        a[n+1].x1=a[n+1].x2=x;a[n+1].h=y;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i].x1>>a[i].x2>>a[i].h;
        }
        sort(a,a+2+n,cmp);
        for(int i=n;i>=0;i--)
        {
            left(i);
            right(i);
        }
        cout<<min(dp[0][0],dp[0][1])<<endl;
    }
}

Longest Ordered Subsequence

2533 -- Longest Ordered Subsequence (poj.org)

思路:lis模板题

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
using namespace std;
const int maxn = 1100;
int a[maxn];
int dp[maxn];
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        memset(dp,0,sizeof dp);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            dp[i]=1;
        }
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=i;j++)
            {
                if(a[j]<a[i])
                {
                    dp[i]=max(dp[i],dp[j]+1);
                }
            }
            ans=max(ans,dp[i]);
        }
        cout<<ans<<endl;
    }
}

Treats for the Cows

3186 -- Treats for the Cows (poj.org)

思路:定义$dp[i][j]$表示左端取i个,右端取j个时获得的总价值之和最大。转移态方程为$dp[i][j]=max(dp[i-1][j]+(i+j)a[i],dp[i][j-1]+(i+j)a[n-j+1])$

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
using namespace std;
const int maxn = 2100;
typedef long long ll;
int a[maxn];
ll dp[maxn][maxn];
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    dp[1][0]=a[1];dp[0][1]=a[n];
    ll ans=0;
    for(int i=0;i<=n;i++)
    {
        for(int j=0;j<=n;j++)
        {
            if(i+j>n) break;
            if(i&&j)
            {
                dp[i][j]=max(dp[i-1][j]+(ll)(i+j)*a[i],dp[i][j-1]+(ll)(i+j)*a[n-j+1]);
                continue;
            }
            if(i) dp[i][j]=dp[i-1][j]+(ll)(i+j)*a[i];
            if(j) dp[i][j]=dp[i][j-1]+(ll)(i+j)*a[n-j+1];
        }
    }
    for(int i=0;i<=n;i++)
    {
        ans=max(ans,dp[i][n-i]);
    }
    cout<<ans<<endl;
}

FatMouse and Cheese

Problem - 1078 (hdu.edu.cn)

思路:读完题目便想到了记忆化搜素,每次搜索四个方向以及移动的距离,用数组$dp[i][j]$记录一下当前状态。

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;
const int maxn = 110;
typedef long long ll;
int n,m;
ll dp[maxn][maxn];
int a[maxn][maxn];
int vis[maxn][maxn];
int ans=0;
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
ll dfs(int x,int y)
{
    if(dp[x][y]) return dp[x][y];
    ll mx=0;
    for(int i=1;i<=m;i++)
    {
        for(int j=0;j<4;j++)
        {
            int x1=x+i*dir[j][0];
            int y1=y+i*dir[j][1];
            if(x1<=0||y1<=0||x1>n||y1>n) continue;
            if(a[x1][y1]<=a[x][y]) continue;
            mx=max(mx,dfs(x1,y1)+a[x1][y1]);
            // cout<<"mx="<<mx<<endl;
        }
    }
    return dp[x][y]+=mx;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        if(n+m==-2) break;
        ans=0;
        memset(vis,0,sizeof vis);
        memset(dp,0,sizeof dp);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                scanf("%d",&a[i][j]);
            }
        }
        dfs(1,1);
        dp[1][1]+=a[1][1];
        printf("%d\n",dp[1][1]);
    }
}

Phalanx

Problem - 2859 (hdu.edu.cn)

思路:这道题是用dp找最大的对称子图。定义$dp[i][j]$表示以坐标$(i,j)$为左下角时最大的对称子图。$dp[i][j]$的状态可以由$dp[i-1][j+1]$的状态转移过来,只要满足$s[i-k][j]==s[i][k+j]$便可不断更新$dp[i][j]$

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
using namespace std;
const int maxn = 1010;
char s[maxn][maxn];
int dp[maxn][maxn];
int main()
{
    int n;
    while(~scanf("%d",&n),n)
    {
        memset(dp,0,sizeof dp);
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                cin>>s[i][j];
            }
        }
        int ans=1;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                dp[i][j]=1;
                if(i==0||j==n-1) continue;
                int m = dp[i-1][j+1];
                for(int k=1;k<=m;k++)
                {
                    if(s[i-k][j]==s[i][k+j])
                        dp[i][j]++;
                    else
                        break;
                }
                ans=max(ans,dp[i][j]);
            }
        }
        cout<<ans<<endl;
    }
}

Milking Time

3616 -- Milking Time (poj.org)

思路:

先对开始时间进行一个升序排序,然后类似一个简单lis

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
using namespace std;
const int maxn = 1e6+10;
typedef long long ll;
struct node{
    int x,y,w;
}a[maxn];
bool cmp(node a,node b)
{
    return a.x<b.x;
}
ll dp[maxn];
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n,m,r;
    cin>>n>>m>>r;
    for(int i=1;i<=m;i++)
    {
        cin>>a[i].x>>a[i].y>>a[i].w;
        a[i].y+=r;
        // dp[i]=a[i].w;
    }
    sort(a+1,a+1+m,cmp);
    for(int i=1;i<=m;i++) dp[i]=a[i].w;
    ll ans=0;
    for(int i=1;i<=m;i++)
    {
        for(int j=1;j<=i;j++)
        {
            if(a[i].x>=a[j].y)
            dp[i]=max(dp[i],dp[j]+a[i].w);
        }
        ans=max(ans,dp[i]);
    }
    for(int i=1;i<=m;i++) ans=max(ans,dp[i]);
    cout<<ans<<endl;
}

Making the Grade

3666 -- Making the Grade (poj.org)

思路:分别考虑构建成不递增的序列和不递减的序列,这里以不递增的序列为例。定义$dp[i][j]$表示前i个数中且第i个数为第j大时所需的最低费用。转移态方程$dp[i][j]=min(dp[i-1][k])+abs(a[i]-b[j])$

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
using namespace std;
const int maxn = 2e3+10;
typedef long long ll;
int a[maxn];
int b[maxn];
ll dp1[maxn][maxn];
ll dp2[maxn][maxn];
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);

    int n;
    ll ans=1ll<<62;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        b[i]=a[i];
    }
    sort(b+1,b+1+n);
    for(int i=1;i<=n;i++)
    {
        ll x=1ll<<62;
        for(int j=1;j<=n;j++)
        {
            x=min(x,dp1[i-1][j]);
            dp1[i][j]=x+abs(a[i]-b[j]);
        }
    }
    for(int i=1;i<=n;i++)
    {
        ans=min(ans,dp1[n][i]);
    }
    reverse(b+1,b+1+n);
    for(int i=1;i<=n;i++)
    {
        ll x=1ll<<62;
        for(int j=1;j<=n;j++)
        {
            x=min(x,dp2[i-1][j]);
            dp2[i][j]=x+abs(a[i]-b[j]);
        }
    }
    for(int i=1;i<=n;i++)
    {
        ans=min(ans,dp2[n][i]);
    }
    cout<<ans<<endl;
}
posted @ 2023-03-05 17:23  Yuuu7  阅读(3)  评论(0编辑  收藏  举报