dp

/*
	hdu 1505 这道题是hdu 1506的加强版,同样时求最大子矩阵面积,但不同之处在于这道题并不是求
	直方图的最大矩阵,而是求一个矩形内的最大子矩阵,主要的做法就是把矩形分成若干层,每一层都是
	求当前层的最大子矩阵面积,这样就转化成了1505 
*/
#include <cstdio>
#include <map>
#include <iostream>
#include<cstring>
#include<bits/stdc++.h>
#define ll long long int
#define M 998244353
using namespace std;
const int inf=0x3f3f3f3f;
int k,m,n;
char mapp[1007][1007];
int h[1007][1007];
int l[1007][1007],r[1007][1007];
int main(){
	cin>>k;
	while(k--){
		cin>>m>>n;
		for(int i=1;i<=m;i++)
			for(int j=1;j<=n;j++){
				cin>>mapp[i][j];
			}
			memset(l,0,sizeof(l));
			memset(r,0,sizeof(r));
			memset(h,0,sizeof(h));
		for(int i=1;i<=m;i++){
			l[i][1]=1;
			r[i][n]=n;
		}	
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++){
				if(mapp[j][i]=='F')
				h[m-j+1][i]=h[m-j+2][i]+1;
				else
				h[m-j+1][i]=0;
			}
		
		for(int i=1;i<=m;i++)
			for(int j=2;j<=n;j++){
				int t=j;
				while(t>1&&h[i][j]<=h[i][t-1])
					t=l[i][t-1];
				l[i][j]=t;
		}
		for(int i=1;i<=m;i++)
			for(int j=n-1;j>=1;j--){
				int t=j;
				while(t<n&&h[i][j]<=h[i][t+1])
					t=r[i][t+1];
				r[i][j]=t;
			}
			ll maxx=0;
		for(int i=1;i<=m;i++)
			for(int j=1;j<=n;j++)
			if((r[i][j]-l[i][j]+1)*h[i][j]*3>maxx){
				maxx=(r[i][j]-l[i][j]+1)*h[i][j]*3;
			}
			
		cout<<maxx<<endl;
			
	}
}
/*
	hdu 1506 找最大子矩阵面积
	不难想到(狗屁)最大子矩阵的面积总是由 一个单位的矩阵 加上 两边更高 的连续矩阵所拼接而成的大矩阵
	理解上面一句话。
	但是不能直接遍历1~n每一个单位的矩阵去试探左右两边的长度,这样保守估计是一个n平方的算法,所以不妨换一种思考方式
	for(ll i=2;i<=n;i++){
			ll t=i;
			while(t>1&&h[i]<=h[t-1])
				t=l[t-1];
			l[i]=t;
		}
	当在搜索下标为i的单位矩阵时,当i-1的下标的单位矩阵高度高于它时,其实我们是已经判断过下标为i-1的单位矩阵的最左端
	下标的,所以这就满足dp的条件,只要把左边各个连续且大于h[i]高度的矩阵的最远下边记录下来即可。 
*/
#include <cstdio>
#include <map>
#include <iostream>
#include<cstring>
#include<bits/stdc++.h>
#define ll long long int
#define M 998244353
using namespace std;
const int inf=0x3f3f3f3f;
ll n,h[100007];
ll l[100007],r[100007];
int main(){
	while(cin>>n){
		if(!n)
		break;
		memset(l,0,sizeof(l));
		memset(r,0,sizeof(r));
		for(ll i=1;i<=n;i++)
			cin>>h[i];
		l[1]=1;
		r[n]=n;      
		//初始化 第一个矩阵左边没有比它更高的矩阵,同理最后一个也一样。 
		for(ll i=2;i<=n;i++){
			ll t=i;
			while(t>1&&h[i]<=h[t-1])
				t=l[t-1];
			l[i]=t;
		}
		for(ll i=n-1;i>=1;i--){
			ll t=i;
			while(t<n&&h[i]<=h[t+1])
				t=r[t+1];
			r[i]=t;
		}
		ll maxn=-1;
		for(ll i=1;i<=n;i++){
			if((r[i]-l[i]+1)*h[i]>maxn)
			maxn=(r[i]-l[i]+1)*h[i];
		}
		cout<<maxn<<endl;
	}
} 
/*	http://acm.hdu.edu.cn/status.php   hdu 1864
	对于浮点类型的质量与价值,因为都为小数点后两位,所以都乘100转化为整型进行dp
	状态转移方程:	dp[j]=max(dp[j],dp[j-weight[i]]+value[i]); 
*/ 
#include <cstdio>
#include <map>
#include <iostream>
#include<cstring>
#include<bits/stdc++.h>
#define ll long long int
#define M 998244353
using namespace std;
const int inf=0x3f3f3f3f;
double q;
int n;
int value[35];
int dp[3000007];
int main(){
	while(cin>>q>>n){
		if(!n)
		break;
		int k=1;
		memset(dp,0,sizeof(dp));
		for(int i=1;i<=n;i++){
			int m;
			cin>>m;
			int a=0,b=0,c=0;
			int flag=1;
			for(int j=1;j<=m;j++){
				char type;
				char temp;
				double val;
				cin>>type>>temp>>val;
				if(type=='A'){
					a+=(int)(val*100);
				}
				else if(type=='B'){
					b+=(int)(val*100);
				}
				else if(type=='C'){
					c+=(int)(val*100);
				}
				else{
					flag=0; break;
				}
			}
			if(!flag||(a+b+c)>100000||a>60000||b>60000||c>60000)
				continue;
			value[k++]=a+b+c;
		}
		for(int i=1;i<k;i++)
			for(int j=(int)(q*100);j>=value[i];j--){
				dp[j]=max(dp[j],dp[j-value[i]]+value[i]);
			}
		//	cout<<(int)(q*100)<<endl;
		double ans=dp[(int)(q*100)]*1.0/100;
		printf("%.2lf\n",ans);
	}
}
/*
		hdu 2955
		一道0-1背包的变形,本来看测试数据以为是直接背包概率,结果wa。
		然后去看题解,大多数人也犯了这样的错误,错误的原因不同的题解有不同的说法,
		我认为 总的被抓概率并不是又各个分概率的和组成的, 这个其实显而易见。
		如 
		1 0.02 
		2 0.03
		被抓的概率显然不是0.5
		而是 1-(1-0.02)*(1-0.03)=0.494
		所以这样看来背包概率显然不合适,所以有另外一个背包金钱的方法。
		dp[j]=max(dp[j],dp[j-money[i]]*(1-chance[i])) 
*/
#include <cstdio>
#include <map>
#include <iostream>
#include<cstring>
#include<bits/stdc++.h>
#define ll long long int
#define M 998244353
using namespace std;
const int inf=0x3f3f3f3f;
double dp[10007];
int money[1007];
double chance[1007];
int main(){
	int t;
	cin>>t;
	while(t--){
		double p;
		int n;
		cin>>p>>n;
		memset(dp,0,sizeof(dp));
		dp[0]=1;
		int sum=0;
		for(int i=1;i<=n;i++){
			cin>>money[i]>>chance[i];
			sum+=money[i];
		}
		for(int i=1;i<=n;i++)
			for(int j=sum;j>=money[i];j--){
				dp[j]=max(dp[j],dp[j-money[i]]*(1-chance[i]));
			}
		for(int i=sum;i>=0;i--){
			if(dp[i]>=(1-p)){
				cout<<i<<endl;
				break;
			}
		}
	}
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值