[Problem] \color{blue}{\texttt{[Problem]}} [Problem]
你的王国里有一条有 n n n 个头的 恶龙
,你希望雇佣一些 骑士
把它杀死(即砍掉所有头)。村里有 m m m 个骑士可以雇佣,一个能力值为 x x x 的骑士可以砍掉恶龙一个直径不超过 x x x 的头,且需要支付 x x x 个金币。如何雇佣骑士才能砍掉龙的所有头,且需要支付的金币最少?注意,一个骑士只能砍一个头且不能被雇佣两次。
输入格式:
输入包含多组数据。
每组数据的第一行为正整数 n n n 和 m ( 1 ≤ n , m ≤ 20000 ) m(1\leq n,m\leq 20000) m(1≤n,m≤20000);
以下 n n n 行每行为一个整数,即恶龙每个头的直径;
以下 m m m 行每行为一个整数,即每个骑士的能力。
输入结束标志为 n = m = 0 n=m=0 n=m=0。
输出格式:
对于每组数据,输出最小花费。
如果无解,输出 Loowater is doomed!
。
[Soluntion] \color{blue}{\texttt{[Soluntion]}} [Soluntion]
贪心。
我们肯定不会花大价钱雇一个非常有能力的骑士来砍一个直径很小的头。由此可以作为贪心的依据。
我们把恶龙的头和骑士的能力值都先从小到大排序。这一步是为了方便下面的处理。
提示:当我们需要处理的信息很乱,但答案与元素间的相对顺序无关时,我们可以考虑通过排序的方法整理数据以方便我们的处理。
我们枚举骑士,如果它可以砍掉恶龙的一个尚未被砍掉的头的话,我们就让它砍。总的时间复杂度是 O ( n + m ) O(n+m) O(n+m) 的。
[code] \color{blue}{\texttt{[code]}} [code]
#define gc getchar()
#define g(c) isdigit(c)
inline int read(){
char c=0;int x=0;bool f=0;
while (!g(c)) f=c=='-',c=gc;
while (g(c)) x=x*10+c-48,c=gc;
return f?-x:x;
}
const int N=2e4+100;
int n,m,a[N],b[N],tot,cur;
int main(){
while (~scanf("%d%d",&n,&m)){
if (n==0&&m==0) break;//结束标志
for(int i=1;i<=n;i++)//枚举恶龙
a[i]=read();//输入恶龙谢谢
for(int i=1;i<=m;i++)//枚举骑士
b[i]=read();//输入骑士信息
tot=0;cur=1;//初始化,十分重要
sort(a+1,a+n+1);//从小到大排序
sort(b+1,b+m+1);//从小到大排序
for(int i=1;i<=m;i++)//枚举骑士
if (b[i]>=a[cur]){//可以杀
cur++;//杀死一个恶龙,要杀下一个
tot+=b[i];//雇佣骑士是要付钱的
if (cur>n) break;//杀死所有恶龙
}
if (cur>n) printf("%d\n",tot);
else puts("Loowater is doomed!");
}
return 0;
}
[Problem] \color{blue}{\texttt{[Problem]}} [Problem]
[Soluntion] \color{blue}{\texttt{[Soluntion]}} [Soluntion]
记 f i , j f_{i,j} fi,j 表示把 i i i 分成 j j j 个数字的和的方案数。
我们可以得到如下的状态转移方程:
f i , j = ∑ k = 0 i f i − k , j − 1 f_{i,j}=\sum\limits_{k=0}^{i} f_{i-k,j-1} fi,j=k=0∑ifi−k,j−1
其含义是,我们把 i − k i-k i−k 分成 j − 1 j-1 j−1 个和,然后再加上一个数 k k k,刚刚好总和就是 i i i,分成了 j j j 份。
总的时间复杂度为 O ( n 2 × k ) O(n^2\times k) O(n2×k),完全可以通过本题 1 ≤ n , k ≤ 100 1 \leq n,k \leq 100 1≤n,k≤100 的数据。
[code] \color{blue}{\texttt{[code]}} [code]
int f[110][110],n,k;
const int mod=1000000;
int main(){
freopen("t1.in","r",stdin);
for(int i=0;i<=100;i++)
f[i][1]=1;//n=i,k=1
for(int j=2;j<=100;j++)
for(int i=0;i<=100;i++)
for(int k=0;k<=i;k++)
(f[i][j]+=f[i-k][j-1])%=mod;
while (~scanf("%d%d",&n,&k)){
if (n==0&&k==0) break;
printf("%d\n",f[n][k]);
}
return 0;
}