USACO 2016 open Silver 解题报告

Sliver1

农夫约翰的N(5<=N<=50000)头牛被定在了平面内的不同的位置。他想用栅栏(平行于xy)围住所有的牛。他想这个栅栏尽可能小(牛在边界上也被视作围住)

他因为牛奶产量低而感到经费紧张,所以他想卖掉三头牛再围起剩下的牛。请算出栅栏围出的最小面积。

输入:

第一行输入n

剩下2-n+1行,输入每头牛的位置。

输出:
最小面积。

示例

input

6

1 1

7 8

10 9

8 12

4 100

50 7

output

12

 

这题和Bronze的第三题差不多。只不过要去掉三头奶牛罢了,既然如此,枚举就不可以了。但是,我们发现,和最小面积相关的就只有去掉外面三层奶牛之后(假如去掉的是中间部分,那么,面积是不会受到影响的),奶牛在x,y轴的最大与最小位置相关。所以,我们用一个DFS,就可以把去掉外面三层所有的状态求出来,再求最小值就可以了。而时间复杂度是O((3^4)*n)。

 
  

#include<algorithm>
#include<climits>
#include<fstream>
#include<iostream>
using namespace std;
const int maxn = 50010;
const int inf = INT_MAX;
struct Tnode {
int x, y, id;
} a1[maxn], a2[maxn];
ifstream fin("reduce.in");
ofstream fout("reduce.out");
int n;
long long ans = inf;
bool used[maxn];
bool byX(Tnode, Tnode);
bool byY(Tnode, Tnode);
void dfs(int);
int main() {
fin >> n;//fout<<n<<endl;return 0;

for(int i = 0; i != n; ++i) {
fin >> a1[i].x >> a1[i].y;
a1[i].id = i;
a2[i] = a1[i];
}

sort(a1, a1 + n, byX);
sort(a2, a2 + n, byY);
dfs(0);
fout << ans << endl;
return 0;
}
bool byX(Tnode i, Tnode j) {
return i.x < j.x;
}
bool byY(Tnode i, Tnode j) {
return i.y < j.y;
}
void dfs(int k) {
if(k == 3) {
int maxx, maxy, minx, miny;
maxx = maxy = -inf;
minx = miny = inf;

for(int i = 0; i != n; ++i)
if(!used[a1[i].id]) {
maxx = max(maxx, a1[i].x);
maxy = max(maxy, a1[i].y);
minx = min(minx, a1[i].x);
miny = min(miny, a1[i].y);
}

ans = min(ans, (long long)(maxx - minx) * (maxy - miny));
return;
}

int i;

for(i = 0; i != n && used[a1[i].id]; ++i);

used[a1[i].id] = true;
dfs(k + 1);
used[a1[i].id] = false;

for(i = n - 1; i != -1 && used[a1[i].id]; --i);

used[a1[i].id] = true;
dfs(k + 1);
used[a1[i].id] = false;

for(i = 0; i != n && used[a2[i].id]; ++i);

used[a2[i].id] = true;
dfs(k + 1);
used[a2[i].id] = false;

for(i = n - 1; i != -1 && used[a2[i].id]; --i);

used[a2[i].id] = true;
dfs(k + 1);
used[a2[i].id] = false;
}

                                Diamond Collector(Silver)

         奶牛Bessie很喜欢闪亮亮的东西(Baling~Baling~),所以她喜欢在她的空余时间开采钻石!她现在已经收集了N颗不同大小的钻石(N<=50,000),现在她想在谷仓的两个陈列架上摆放一些钻石。

    Bessie想让这些陈列架上的钻石保持相似的大小,所以她不会把两个大小相差K以上的钻石同时放在一个陈列架上(如果两颗钻石的大小差值为K,那么它们可以同时放在一个陈列架上)。现在给出K,请你帮Bessie确定她最多一共可以放多少颗钻石在这两个陈列架上。

 

输入格式(diamond.in:

    第一行输入两个值NK0<=K<10,000)

         接下来N行,每行是一个整数,分别表示第1~N颗钻石的大小。

         数据保证钻石的大小为正数且不超过10,000.

 

输出格式(diamond.out):

         输出仅一个数,为Bessie能在这两个陈列架上摆的钻石总数的最大值。

 

输入样例:

7 3

10

5

1

12

9

5

14

 

输出样例:

5

 

这题就有些难度了。首先,我们可以预处理,记l[i]为在区间[1,i]里最多能放多少个钻石(其中包括i),r[i]为区间[i,n]里最多能放多少个钻石(其中也包括i),这个可以用单调队列来实现。然后,我们就枚举划分点,也就是说,记这个划分点为k,第一个陈列架上,在前k个选能摆放钻石个数的最大值,而第二个陈列架上,放的是从k到n能摆放钻石的最大值,这两个最大值,也是可以预处理的。最后,只要输出这两个最大值的和的最大值就可以了。

 
  

#include <cstdio> #include <algorithm> #include <iostream> using namespace std; int n,k; int i,j; int ans; int a[50010],l[50010],r[50010],ll[50010],rr[50010]; int main() { freopen("diamond.in","r",stdin); freopen("diamond.out","w",stdout); scanf("%d%d",&n,&k); for(i=1;i<=n;i++) scanf("%d",&a[i]); sort(a+1,a+n+1); for(i=1;i<=n;i++) l[i]=1; j=1; for(i=1;i<=n;i++) { for(; j<=n;j++) { if(a[j]-a[i]<=k) { l[j]=max(l[j],j-i+1); } else break; } r[i]=j-i; } ll[1]=l[1]; for(i=2;i<=n;i++) ll[i]=max(ll[i-1],l[i]); //rr[n]=r[n]; for(i=n-2;i>=1;i--) rr[i]=max(rr[i+1],r[i+1]); for(i=1;i<=n;i++) ans=max(ans,rr[i]+ll[i]); printf("%d\n",ans); return 0; }



Sliver3

【题目描述】

FJ和他的奶牛们正在计划离开小镇做一次长的旅行,同时FJ想临时地关掉他的农场以节省一些金钱。

 

这个农场一共有被用M条双向道路连接的N个谷仓(1<=N,M<=3000)。为了关闭整个农场,FJ 计划每一次关闭掉一个谷仓。当一个谷仓被关闭了,所有的连接到这个谷仓的道路都会被关闭,而且再也不能够被使用。

 

FJ现在正感兴趣于知道在每一个时间(这里的“时间”指在每一次关闭谷仓之后的时间)时他的农场是否是“全连通的”——也就是说从任意的一个开着的谷仓开始,能够到达另外的一个谷仓。注意自从某一个时间之后,可能整个农场都开始不会是“全连通的”。

 

【输入格式】

输入的第一行是NM。下面的M行每行都描述了一条连接两个谷仓的双向路径的两个端点(输入的点保证在1...N的范围内),最后的N行是一个1...N的排列,描述每一个谷仓被关闭的顺序。

 

【输出顺序】

输出一共有N行,每行可以是“YES”或者“NO”。第一行表示一开始时整个农场是否是“全连通的”,然后第i+1行表示在第i次的关闭谷仓之后整个农场是否是“全连通的”。

 

【样例输入】

4 3

1 2

2 3

3 4

3

4

1

2

 

 

【样例输出】

YES
NO
YES
YES

 

这题是一道水题,因为数据只有3000,而金牌组的那一题n<=200000,至于数据大时怎么做,我在金牌组那里会讲。在这题当中,只要每次把边删掉,在判断一下图是否全联通就可以了。而判断图是否联通可以用DFS用O(n)的时间就算出来了。所以,时间复杂度是O(N*M)。

 

 
  

#include <cstdio> #include <vector> #include <iostream> #include <cstring> using namespace std;

bool b[100100],b1[100010]; int num[100010]; vector<int > f[3010]; int n,m,root; int x,y; int sum;

void dfs(int k) {  if(b1[k]==1||b[k]==1) return;  sum++; b1[k]=1;  for(int i=0;i<f[k].size();i++)   dfs(f[k][i]); } int main() {  freopen("closing.in","r",stdin);  freopen("closing.out","w",stdout);    memset(b,0,sizeof(b));  scanf("%d%d",&n,&m);    for(int i=1;i<=m;i++)  {   scanf("%d%d",&x,&y);   f[x].push_back(y);   f[y].push_back(x);  }  for(int i=1;i<=n;i++) scanf("%d",&num[i]);    root=num[n];  for(int i=1;i<=n;i++)  {   memset(b1,0,sizeof(b1));      sum=0;      //printf("%d:",num[i]);      dfs(root);      if(sum==n-i+1) printf("YES\n");   else printf("NO\n");      b[num[i]]=1;  }

 return 0; }

 
  

 

转载于:https://www.cnblogs.com/ouqingliang/p/9245316.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值