[ CodeVS冲杯之路 ] P2456

  不充钱,你怎么AC?

  题目:http://codevs.cn/problem/2456/

  用贪心的思想,木材当然要尽量分成多的木板,而大的木材能够分成大木板,但是小的木材不一定能够分成大的木板,所以木板和木材都是从小到大开始选,然后要保证剩余的木材最少

  那么将木板和木材排序,对于每个木材,把能够分的小木板尽量分掉,如果遇到更大的木板则把最小的木板腾出来,然后在加上,这样保证剩余的木材最少

  因为是上午写得这道题,思路可能不连贯了,代码应该描述的很清楚

  虽然贪心在CodeVS上可以过,但是它是有数据可以卡掉的,而正解是DFS

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 using namespace std;
 8
 9 const int N=51,M=1024;
10 int a[N],b[M],next[M];
11 bool f[M];
12 int main()
13 {
14     int n,i,j,m,k,now,ans=0,x,y;
15     scanf("%d",&n);
16     for (i=1;i<=n;i++) scanf("%d",&a[i]);
17     sort(a+1,a+1+n);
18     scanf("%d",&m);
19     for (i=1;i<=m;i++) scanf("%d",&b[i]);
20     sort(b+1,b+1+m);
21     for (i=1;i<=n;i++)
22         {
23             now=a[i];
24             for (j=0;j<=m;j++) next[j]=0;
25             for (j=1;j<=m;j++)
26                 {
27                     if (f[j]) continue;
28                     if (now>=b[j])
29                         {
30                             now-=b[j];
31                             f[j]=1;
32                             ans++;
33                             next[j]=next[0];
34                             next[0]=j;
35                         }
36                     else
37                         {
38                             k=x=0;
39                             while (now+b[next[k]]>=b[j]) k=next[x=k];
40                             if (k)
41                                 {
42                                     next[x]=next[k];
43                                     f[k]=0;
44                                     f[j]=1;
45                                     next[j]=next[0];
46                                     next[0]=j;
47                                     now+=b[k]-b[j];
48                                 }
49                         }
50                 }
51         }
52     printf("%d\n",ans);
53     return 0;
54 }

  下面是DFS的正解,贴的别人的代码

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 using namespace std;
 8
 9 #define N 1100
10
11 int n,m;
12 int sum1,ans;
13 int tim,res;
14
15 int a[N],b[N],c[N],sum[N];
16
17 int work(int x,int k)
18 {
19     if (!x)
20         return true;
21     if (tim>res)
22         return false;
23     for (int i=k;i<=n;i++)
24         if (a[i]>=b[x])
25         {
26             a[i]-=b[x];
27             if (a[i]<b[1])
28                 tim+=a[i];
29             if (b[x]==b[x-1])
30             {
31                 if (work(x-1,i))
32                     return true;
33             }
34             else if (work(x-1,1))
35                 return true;
36             if (a[i]<b[1])
37                 tim-=a[i];
38             a[i]+=b[x];
39         }
40     return false;
41 }
42
43 int main()
44 {
45     scanf("%d",&n);
46     for (int i=1;i<=n;i++)
47         scanf("%d",&a[i]),sum1+=a[i],c[i]=a[i];
48     scanf("%d",&m);
49     for (int i=1;i<=m;i++)
50         scanf("%d",&b[i]);
51     sort(a+1,a+n+1);
52     sort(b+1,b+m+1);
53     for (int i=1;i<=m;i++)
54         sum[i]=b[i]+sum[i-1];
55     int l=0,r=m;
56     while (l!=r)
57     {
58         int mid=(l+r+1)>>1;
59         tim=0;
60         res=sum1-sum[mid];
61         if (work(mid,1))
62             l=mid;
63         else
64             r=mid-1;
65         for (int i=1;i<=n;i++)
66             a[i]=c[i];
67     }
68     printf("%d\n",l);
69     return 0;
70 }
时间: 2024-10-13 00:28:33

[ CodeVS冲杯之路 ] P2456的相关文章

[ CodeVS冲杯之路 ] P2492

不充钱,你怎么AC? 题目:http://codevs.cn/problem/2492/ 在此先orz小胖子,教我怎么路径压缩链表,那么这样就可以在任意节点跳进链表啦(手动@LCF) 对于查询操作,直接树状数组(以下简称BIT)维护,修改操作就一个个暴力开方搞,再用差值单点更新BIT 不过这样会TLE,要加一点优化对不对,正如开头所说的路径压缩链表 路径压缩链表其实就是个并查集,在普通的链表里,删去两个连续的节点后会是下面这种情况,如删去2,3 当访问 2 的时候,会跳到3,但 3 已经删除了,

[ CodeVS冲杯之路 ] P1368

不充钱,你怎么AC? 题目:http://codevs.cn/problem/1368/ 嗯……泡泡堂,很劲啊,其实就是个盗版的田忌赛马 http://www.cnblogs.com/hyfer/p/5853381.html 这边博客讲得很好啊,虽然不是这道题,但是方法是完全类似的 你把田忌赛马看懂了,泡泡堂就自然解出来了 1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<c

[ CodeVS冲杯之路 ] P1169

不充钱,你怎么AC? 题目:http://codevs.cn/problem/1169/ 感觉这题目好恐怖,莫名其妙乱码一堆就AC了…… 它看上去是两个子问题,实际上可以看成从起点找两条不相交的路径使得经过的数和最大 用 f[i][j][k][l] 表示第一条走到了 (i,j) 第二条走到了 (k,l) 目标状态是 f[n][m-1][n-1][m] 一开始我也没仔细去想,就莫名其妙码了一堆交上去了,本以为会WA,结果A了?! 后面我仔细证明了一下,它是这样的 首先 l 是从 j+1 开始的,这

[ CodeVS冲杯之路 ] P3955

不充钱,你怎么AC? 题目:http://codevs.cn/problem/3955/ 最长上升子序列的加强版,n 有1000000,n 方的 DP 肯定会 TLE,那么用二分栈维护 二分栈我讲不好啊,交给他吧 http://www.cnblogs.com/Booble/archive/2010/11/27/1889482.html 1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #includ

[ CodeVS冲杯之路 ] P1197

不充钱,你怎么AC? 题目:http://codevs.cn/problem/1197/ 密钥的字母可以全转换为小写字母,然后一一映射,a→0,b→1,c→2,依此类推 对于密文只需将每一位减去对应密钥的映射,如果小于 a 或 A 则再将它加上 26 即可 1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<cmath> 5 #include<iostream>

[ CodeVS冲杯之路 ] P1294

不充钱,你怎么AC? 题目:http://codevs.cn/problem/1294/ 随手一打就是这么漂亮的全排列,想当年我初一还是初二的时候,调了1个多小时才写出来(蒟蒻一枚) 直接DFS每次枚举当前数字,记得判断是否重复,取完后打上标记并保存当前位置的数,最后到n+1层时打出来 因为极限数据的方案比较多,所以可以加上输出优化,不过不加也不会TL 上面那个是加了读入优化的,快了将近3倍 1 #include<cstdio> 2 #include<cstdlib> 3 #inc

[ CodeVS冲杯之路 ] P3145

 不充钱,你怎么AC? 题目:http://codevs.cn/problem/3145/ 经典的汉诺塔问题 我们移动的时候,如果是最小的1号就可以直接移动,否则先将上面的x-1号先移动到借用塔上,然后将x号移动到目标塔,最后将借用塔上的x-1号移动到目标塔,每次移动都需要借用一个借用塔,此塔为不同于出发塔和目标塔的那一个,递归做即可 次数的话个人比较懒,直接输出2n-1,就不在移动的时候统计次数了 1 #include<cstdio> 2 #include<cstdlib> 3

[ CodeVS冲杯之路 ] P3143

 不充钱,你怎么AC? 题目:http://codevs.cn/problem/3143/ 大水题一道,只要会遍历,这里讲一下思路 先序遍历:先输出,然后左儿子,最后右儿子 中序遍历:先左儿子,再输出,最后右儿子 后序遍历:先左儿子,然后右儿子,最后输出 1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<cmath> 5 #include<iostream>

[ CodeVS冲杯之路 ] P1092

不充钱,你怎么AC? 题目:http://codevs.cn/problem/1092/ 嗯,这道题有一定难度啊,需要先用扩展欧几里得算法求出逆元,然后按照大小构一颗带边权为小时数的树 树链剖分后在树上DP,设f[i][j]为以 i 为根 j 为子树的最小的那一天 注意DP方程是有单调性的,可以用动态仙人掌维护,最后答案容斥一下即可 目测代码量8k+ 1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4