1027 -【校内训练赛】 - LOJ

题一

令人吐血的一道简单题
不(wang)知(ji)道(le)怎么存 1 0 9 10^9 109大小的0/1数组
B i t s e t Bitset Bitset B i t s e t Bitset Bitset B i t s e t Bitset Bitset B i t s e t Bitset Bitset
你说要是从未知道,这倒是能理解
可关键是,我不但知道而且还写过博客。虽然当时没怎么注意!!!!被自己气到了╭(╯^╰)╮
再来重述一遍:
以后要是想存很大很大的数组(注意只能是0/1),就可以考虑用Bitset,因为这个Bitset八位才占一个Byte!!!

考场心路历程:
啊啊啊,这个1e9怎么搞啊???
Map??
改了半天,慢得一啊·
Unordered_Map??
好像还是一样慢
算了,放弃了
还是暴力吧

题二

是真的很棒啊!!!
这种分配问题第一次接触,不是很好理解(还是费了蛮久的脑子)
先考虑一个比较简单的问题:
现在有 n n n个任务,分配给 x x x 个机器去做,每个机器耗时 a [ i ] a[i] a[i],求完成所有任务的最小时间
这个可以贪心来做
相当于每个机器我都先分配一个任务,然后从中选择最先结束的那个机器,然后再分配任务给他,继续从中找最小的,找 n n n次,就得到答案了
画个图吧:
这是一开始每个机器完成一个任务的时间
在这里插入图片描述
然后第一次会选到第2个机器,然后变成这样
在这里插入图片描述
然后就会选到1啦,这时1的时间就是完成两个任务的最优时间了
具体实现的话就是用

然而这道题还需要烘干机?
也就是说这个任务的完成要分成两步
完成第一步后才能完成第二步
那么我们对于这两个部分都按照贪心搞一遍(模拟上述步骤,就是假设分别把 n n n个任务丢给他们做,求出每个部分的最优时间)
由于我们这个最优时间是不加任何条件的
所以我们将两个部分拼起来,得到的就是最优解了
还有一点,因为最后两个部分拼起来是求 m a x ( a i + b j ) max(a_i+b_j) maxai+bj
我们希望这个值尽量小
就可以用到排序不等式的思想
最优值肯定是 m a x ( a [ 1 ] + b [ n ] , a [ 2 ] + b [ n − 1 ] , a [ 3 ] + b [ n − 2 ] . . . . . . , a [ n ] + b [ 1 ] ) max(a[1]+b[n],a[2]+b[n-1],a[3]+b[n-2]......,a[n]+b[1]) max(a[1]+b[n],a[2]+b[n1],a[3]+b[n2]......,a[n]+b[1])
然后的然后就完啦

题目来源:LOJ 6035


题三

这个dp是真的秀,复杂度 O ( n 5 ) O(n^5) O(n5)(当然是不满的)
定义: f [ i ] [ j ] f[i][j] f[i][j]表示取出 i − j i-j ij这段区间所需要消耗的最小代价
g [ s ] [ t ] [ i ] [ j ] g[s][t][i][j] g[s][t][i][j]表示达到 s − t s-t st这段区间中最小值为 i i i,最大值为 j j j所需要的最小代价
具体实现的话,使用了滚动数组,减少了第一维

转移:(一点也不显然……)
直接看代码(我不会口胡)
1.先离散化(这样 g [ ] g[] g[]中的i,j就保证在50以内了)

#include<bits/stdc++.h>
#define in read()
#define N 100009
using namespace std;
inline int read(){
	char ch;int f=1,res=0;
	while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
	while(ch>='0'&&ch<='9'){
		res=(res<<3)+(res<<1)+ch-'0';
		ch=getchar();
	}
	return f==1?res:-res;
}
int n,a,b;
int w[55],val[55];
int g[55][55][55],f[55][55];
void Min(int &x,int y){ y<x?x=y:0;}
int main(){
	n=in;a=in;b=in;
	int i,j,k;
	for(i=1;i<=n;++i) w[i]=val[i]=in;
	int maxn=n;
	sort(val+1,val+maxn+1);maxn=unique(val+1,val+maxn+1)-val-1;
	for(i=1;i<=n;++i) w[i]=lower_bound(val+1,val+maxn+1,w[i])-val;
	int len,l,r;
	for(i=1;i<=n;++i) f[i][i]=a;//取出自己,所花代价
	for(len=2;len<=n;++len){//区间长度作为阶段
		for(l=1,r=len;r<=n;++l,++r){//当前的状态
			for(int t=l;t<=r;++t)
				for(i=maxn;i>=1;--i)
					for(j=maxn;j>=i;--j)
						g[t][i][j]=(1<<30);//这三层循环初始化
			g[l][w[l]][w[l]]=0;
			for(int t=l;t<r;++t)///
				for(i=maxn;i>=1;--i)
					for(j=maxn;j>=i;--j)
						if(g[t][i][j]!=(1<<30)){
							Min(g[t+1][min(i,w[t+1])][max(j,w[t+1])],g[t][i][j]);
							for(int p=r;p>t;--p) Min(g[p][i][j],g[t][i][j]+f[t+1][p]);
						}
			f[l][r]=(1<<30);
			for(i=maxn;i>=1;--i) for(j=maxn;j>=i;--j) Min(f[l][r],g[r][i][j]+a+b*(val[i]-val[j])*(val[i]-val[j]));
			
		}
	}
	
	cout<<f[1][n];
	return 0;
}
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值