USACO 2016 US Open Contest总结

比赛链接

T1 Splitting the Field

题目链接

题目大意:平面上有一些点,问用一个矩形把他们都框起来比用两个矩形都框起来花费面积要大多少(矩形可以使一条线)。

思路:考虑一个矩形变成两个矩形,要么是竖着切一刀要么是横着切一刀。所以我们统计一个点左边和一个点右边最高最远的点在哪里,枚举求出答案即可。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>
#include <algorithm>
#include <list>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
using namespace std;
#define clc(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int N = 50010;
const int M = 1e6+10;
const int MOD = 1e9+7;
#define LL long long
#define LB long double
#define mi() (l+r)>>1
double const pi = acos(-1);
const double eps = 1e-8;
void fre() {
    freopen("in.txt","r",stdin);
}
struct point{
    int x,y;
    point(int x_=0,int y_=0):x(x_),y(y_){}
    bool operator < (const point &a) const{
        return x==a.x?y<a.y:x<a.x;
    }
}p[N];
int l[N],r[N],l1[N],r1[N];
int n;
LL ans;
void work(){
    clc(l,inf),clc(r,-inf),clc(l1,inf),clc(r1,-inf);
    sort(p+1,p+n+1);
    for(int i=1;i<=n;i++){
        l[i]=min(l[i-1],p[i].y),r[i]=max(r[i-1],p[i].y);
    }
    for(int i=n;i>=1;i--){
        l1[i]=min(l1[i+1],p[i].y),r1[i]=max(r1[i+1],p[i].y);
    }
    for(int i=2;i<=n;i++){
        LL tem=(LL)(r[i-1]-l[i-1])*(p[i-1].x-p[1].x)+(LL)(r1[i]-l1[i])*(p[n].x-p[i].x);
        ans=min(tem,ans);
    }
}
int main(){
    int minx=inf,miny=inf,maxx=-inf,maxy=-inf;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&p[i].x,&p[i].y);
        minx=min(minx,p[i].x);
        maxx=max(maxx,p[i].x);
        miny=min(miny,p[i].y);
        maxy=max(maxy,p[i].y);
    }
    ans=(LL)(maxx-minx)*(maxy-miny);
    LL ans1=ans;
    work();
    for(int i=1;i<=n;i++) swap(p[i].x,p[i].y);
    work();
    printf("%lld\n",ans1-ans);
    return  0;
}

T2 Closing the Farm

题目链接

题目大意:一张图,不停删掉其中一个点,问每次删之前图是否联通。

思路:因为数据较小,所以采用了BFS,暴力删点暴力判断是否联通。。。。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstdlib>
#include<map>
#include<vector>
#include<ctime>
#include<stack>
#include<cctype>
#include<set>
#define mp make_pair
#define pa pair<int,int>
#define INF 0x3f3f3f3f
#define inf 0x3f
#define fi first
#define se second
#define pb push_back
#define ll long long
#define ull unsigned long long

using namespace std;

inline ll read()
{
    long long f=1,sum=0;
    char c=getchar();
    while (!isdigit(c)){if (c=='-') f=-1;c=getchar();}
    while (isdigit(c)){sum=sum*10+c-'0';c=getchar();}
    return sum*f;
}
const int MAXN=200010;
const int MAXM=500010;
struct edge
{
    int next,to;
};
edge e[MAXM];
int head[MAXN],cnt;
void addedge(int u,int v)
{
    e[++cnt].next=head[u];
    e[cnt].to=v;
    head[u]=cnt;
}
bool used[MAXN];
bool inqueue[MAXN];
int dis[MAXN],n;
queue <int> q;
bool spfa()
{
    memset(dis,inf,sizeof(dis));
    for (int i=1;i<=n;i++)
        if (!used[i])
        {
            q.push(i),dis[i]=0,inqueue[i]=1;
            break;
        }
    while (!q.empty())
    {
        int x=q.front();
        q.pop();
        for (int i=head[x];i;i=e[i].next)
        {
            int v=e[i].to;
            if (used[v]) continue;
            if (dis[v]>dis[x]+1)
            {
                dis[v]=dis[x]+1;
                if (!inqueue[v])
                    q.push(v),inqueue[v]=1;
            }
        }
        inqueue[x]=0;
    }
    for (int i=1;i<=n;i++)
        if (!used[i])
            if (dis[i]==INF)
                return 0;
    return 1;
}
int main()
{
    int m;
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        addedge(u,v),addedge(v,u);
    }
    if (spfa()) cout<<"YES"<<endl;
    else cout<<"NO"<<endl;
    for (int i=1;i<n;i++)
    {
        int x;
        scanf("%d",&x);
        used[x]=1;
        if (spfa()) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    scanf("%d",&cnt);
    return 0;
}

T3 248

题目链接

题目大意:在一个 1 × N 的地图中玩2048,合并相邻两个格产生的新数是原数+1,求最大合并出来哪个数。

思路:此题非常经典。。感觉好久之前就见过了。
区间DP
- f [ i ] [ j ] 表示区间 [ i , j ] 全部合并产生的最大的数是多少。
- 转移时枚举断点k,看 f [ i ] [ j ] f [ k + 1 ] [ j ] 是否相等决定能否转移。

难得1A DP题。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstdlib>
#include<map>
#include<vector>
#include<ctime>
#include<stack>
#include<cctype>
#include<set>
#define mp make_pair
#define pa pair<int,int>
#define INF 0x3f3f3f3f
#define inf 0x3f
#define fi first
#define se second
#define pb push_back
#define ll long long
#define ull unsigned long long

using namespace std;

inline ll read()
{
    long long f=1,sum=0;
    char c=getchar();
    while (!isdigit(c)){if (c=='-') f=-1;c=getchar();}
    while (isdigit(c)){sum=sum*10+c-'0';c=getchar();}
    return sum*f;
}
const int MAXN=2500;
int f[MAXN][MAXN],a[MAXN];
int main()
{
    freopen("248.in","r",stdin);
    freopen("248.out","w",stdout);
    int n;
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    int ans=0;
    for (int i=1;i<=n;i++)
        f[i][i]=a[i],ans=max(ans,a[i]);
    for (int len=2;len<=n;len++)
    {
        for (int l=1;l<=n;l++)
        {
            int r=l+len-1;
            for (int k=l;k<r;k++)
            {
                if (f[l][k]==f[k+1][r])
                {
                    f[l][r]=max(f[l][r],f[l][k]+1);
                    ans=max(ans,f[l][r]);
                }
            }
        }
    }
    cout<<ans;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/szh_0808/article/details/80496701