dp趣题

dp趣题

[CEOI2017]Chase

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<set>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 7;
int n,m;
int p[maxn];
ll sum[maxn];
int l,last[maxn],other[maxn<<1],pre[maxn<<1];
ll ans,up[maxn][101],down[maxn][101];
vector<int> e[maxn];
void add(int x,int y){
	l ++;
	pre[l] = last[x];
	last[x] = l;
	other[l] = y;
}
void dfs(int x,int fa){
	for(int i = 1;i <= m ;i ++){
		up[x][i] = sum[x];
		down[x][i] = sum[x] - p[fa];
	}
    for(int i = 0;i < e[x].size();i ++){
    	int v = e[x][i];
    	if(v == fa)continue;
    	dfs(v,x);
    	for(int j = 1;j < m;j ++)
    	ans = max(ans,up[x][j] + down[v][m - j]);
    	for(int j = 1;j <= m;j ++){
    		up[x][j] = max(up[x][j],max(up[v][j],up[v][j-1] + sum[x] - p[v]));
    		down[x][j] = max(down[x][j],max(down[v][j],down[v][j-1] + sum[x] - p[fa]));
    	}
    }
    reverse(e[x].begin(),e[x].end());
    for(int i = 1;i <= m ;i ++){
		up[x][i] = sum[x];
		down[x][i] = sum[x] - p[fa];
	}
    for(int i = 0;i < e[x].size();i ++){
    	int v = e[x][i];
    	if(v == fa)continue;
    	for(int j = 1;j < m;j ++)
    	ans = max(ans,up[x][j] + down[v][m - j]);
    	for(int j = 1;j <= m;j ++){
    		up[x][j] = max(up[x][j],max(up[v][j],up[v][j-1] + sum[x] - p[v]));
    		down[x][j] = max(down[x][j],max(down[v][j],down[v][j-1] + sum[x] - p[fa]));
    	}
    }
    ans = max(ans,max(up[x][m],down[x][m]));
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n ;i ++){
		scanf("%d",&p[i]);
	}
	for(int i = 1;i < n ;i ++){
		int a,b;
		scanf("%d%d",&a,&b);
		e[a].push_back(b);
		e[b].push_back(a);
		sum[a] += p[b];
		sum[b] += p[a];
	}
	dfs(1,0);
	cout<<ans<<endl;
	return 0;
}

SP703 SERVICE - Mobile Service

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<set>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
int t;
int n,m;
int dp[1010][201][210];
int p[1010];
int a[201][201];
int main()
{
	scanf("%d",&t);
	while(t --){
		scanf("%d%d",&m,&n);
		memset(dp,0x3f,sizeof dp);
		for(int i = 1;i <= m;i ++){
			for(int j = 1;j <= m;j ++){
				scanf("%d",&a[i][j]);
			}
		}
		for(int i = 1;i <= n ;i ++){
			scanf("%d",&p[i]);
		}
		dp[0][1][2] = 0;p[0] = 3;
		for(int i = 0;i < n ;i ++){
			for(int j = 1;j <= m;j ++){
				for(int k = 1;k <= m;k ++){
					int d = p[i];
					if(j == k || j == d || k == d)continue;
					if(j != p[i+1] && k != p[i+1])
					dp[i+1][j][k] = min(dp[i+1][j][k],dp[i][j][k] + a[d][p[i+1]]);
					if(k != p[i+1] && d != p[i+1])
					dp[i+1][d][k] = min(dp[i+1][d][k],dp[i][j][k] + a[j][p[i+1]]);
					if(j != p[i+1] && d != p[i+1])
					dp[i+1][j][d] = min(dp[i+1][j][d],dp[i][j][k] + a[k][p[i+1]]);
				}
			}
		}
		int ans = 1e9 + 7;
		for(int i = 1;i <= m;i ++)
		for(int j = 1;j <= m;j ++)
		if(i != j)ans = min(dp[n][i][j],ans);
		printf("%d\n",ans);
	}
	return 0;
}

[HNOI2010]合唱队

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<set>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn = 1001;
const int mo = 19650827;
int n;
int a[maxn],dp[maxn][maxn][2];
int main()
{
	scanf("%d",&n);
	for(int i = 1;i <= n ;i ++){
		scanf("%d",a + i);
	}
	for(int i = 1;i <= n ;i ++)
	dp[i][i][0] = 1;
	for(int l = 2;l <= n;l ++){
		for(int i = 1;i <= n - l + 1;i ++){
			int j = i + l - 1;
			if(a[i] < a[i+1])(dp[i][j][0] += dp[i+1][j][0])%mo;
			if(a[i] < a[j])(dp[i][j][0] += dp[i+1][j][1])%mo;
			if(a[j] > a[j-1])(dp[i][j][1] += dp[i][j-1][1])%mo;
			if(a[j] > a[i])(dp[i][j][1] += dp[i][j-1][0])%mo;
			dp[i][j][0] %= mo;dp[i][j][1] %= mo;
		}
	}
	printf("%d",(dp[1][n][0] + dp[1][n][1])%mo);
	return 0;
}

货物分组

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<set>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn = 5001;
int n,m;
ll sum[maxn];
int a[maxn],ans = 1e9 + 7;
ll dp[maxn];
int main()
{
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;i ++){
		scanf("%d",&a[i]);
		sum[i] = sum[i - 1] + a[i];
	}
	memset(dp,0x3f,sizeof dp);
	dp[0] = 0;
	for(int i = 1;i <= n;i ++){
		int mx = 0,mn = 1e9 + 7;
		for(int j = i;j >= 1;j --){
			if(sum[i] - sum[j-1] > m)break;
			mx = max(mx,a[j]);
			mn = min(mn,a[j]);
			dp[i] = min(dp[i],dp[j-1] + mx - mn + sum[n] - sum[j-1]);
		}
	}
	cout<<dp[n]<<endl;
	return 0;
}

T107511 花朵

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<set>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn = 5001;
int n;
int a[maxn],sum[maxn];
int dp[maxn],ans = 1e9 + 7,mn[maxn];
int main()
{
	scanf("%d",&n);
	for(int i = 1;i <= n;i ++){
		scanf("%d",&a[i]);
		sum[i] = sum[i-1] + a[i];
	}
	memset(dp,0x3f,sizeof dp);
	mn[1] = a[1];
	dp[0] = 0;
	for(int i = 1;i <= n;i ++){
		for(int j = i - 1;j >= 0;j --){
			if(sum[i] - sum[j] >= mn[j]){
				if(dp[i] > dp[j] + i - j - 1){
					dp[i] = dp[j] + i - j - 1;
					mn[i] = sum[i] - sum[j];
				}
			}
		}
	}
	cout<<dp[n]<<endl;
	return 0;
}
/*
long long
线段树四倍
写代码时请注意:
	1.是否要开Long Long?数组边界处理好了么?
	2.实数精度有没有处理?
	3.特殊情况处理好了么?
	4.做一些总比不做好.
思考提醒:
	1.最大值和最小值问题可不可以用二分答案?
	2.有没有贪心策略?否则能不能dp?
*/

【十连测 Day 1】分组

//SRTTQL%%%%%%%%%%%
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<set>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
inline int read()
{
    char ch=getchar();int x=0,f=1;
    while(ch<'0' || ch>'9') {
       if(ch=='-') f=-1;
      	  ch=getchar();
    }
    while(ch<='9' && ch>='0') {
       x=x*10+ch-'0';
       ch=getchar();
    }
    return x*f;
}
inline ll readl()
{
    char ch=getchar();ll x=0,f=1;
    while(ch<'0' || ch>'9') {
       if(ch=='-') f=-1;
      	  ch=getchar();
    }
    while(ch<='9' && ch>='0') {
       x=x*10+ch-'0';
       ch=getchar();
    }
    return x*f;
}
const int maxn = 2001;
ll dp[maxn][maxn];
struct node
{
	int s,w,p;
}a[100210];
int n,k;
bool cmp(node a,node b)
{
	if(a.w == b.w)
	return a.p < b.p;
	return a.w < b.w;
}
int main()
{
	n = read(),k = read();
	for(int i = 1;i <= n ;i ++)
	{
		a[i].w = read(),a[i].s = read(),a[i].p = read();
		if(a[i].p == 1)a[i].p = 3;
		else if(a[i].p == 3)a[i].p = 2;
		else if(a[i].p == 2)a[i].p = 1;
	}
	if(2*k > n){cout<<-1;return 0;}
	sort(a + 1,a + 1 + n,cmp);
	for(int i = 0;i <= k ;i ++)
	for(int j = 0;j <= k; j ++)
	dp[i][j] = 1e18 + 7;
	dp[0][0] = 0;
	for(int i = 1;i <= n ; i++)
	{
		for(int j = k;j >= 1; j--)
		{
			for(int kk = 0;kk <= j ;kk++)
			{
				if(a[i].p == 2 || a[i].p == 1)
				{
					if(kk > 0)
					dp[j][kk] = min(dp[j][kk],dp[j-1][kk-1] + a[i].s);
				}
				if(a[i].p == 3 || a[i].p == 2)
				{
					if(kk < j)
					dp[j][kk] = min(dp[j][kk],dp[j][kk+1] + a[i].s);
				}
			}
		}
	}
	if(dp[k][0] >= 1e18){cout<<-1<<endl;return 0;}
	printf("%lld",dp[k][0]);
	return 0;
}
/*
long long
线段树四倍
写代码时请注意:
	1.是否要开Long Long?数组边界处理好了么?
	2.实数精度有没有处理?
	3.特殊情况处理好了么?
	4.做一些总比不做好.
思考提醒:
	1.最大值和最小值问题可不可以用二分答案?
	2.有没有贪心策略?否则能不能dp?
*/

posted @ 2020-01-25 16:01  wtz2333  阅读(129)  评论(0)    收藏  举报