题一
令人吐血的一道简单题
不(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)
max(ai+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[n−1],a[3]+b[n−2]......,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
i−j这段区间所需要消耗的最小代价
g
[
s
]
[
t
]
[
i
]
[
j
]
g[s][t][i][j]
g[s][t][i][j]表示达到
s
−
t
s-t
s−t这段区间中最小值为
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;
}