2022-2023 ICPC Brazil Subregional Programming Contest补题

C Cutting with Lasers

题意

木材板材的激光切割机的激光头只能在水平和垂直两个方向移动。编程机器执行一个非空的连续切割序列,从同一点开始和结束。除第一次外,序列中的每一次切割都从上一次切割结束的点开始。切边不得接触待切纸的边缘。求解由一系列切割产生的最大一块的面积,只考虑由切割线形成的多边形中所包含的片段。

代码

#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
int n;
int col[1005][1005],row[1005][1005];
bool vis[1005][1005];
int cal[1000005];
struct node
{
    int x;
    int y;
}point[10005];
struct edge
{
    node q;
    node z;
}bian[10005];
bool check (int x, int y)
{
	return (1 <= x) && (1000 >= x) && 
            (1 <= y) && (1000 >= y);
}
int getpos(int x,int y)
{
    return x*1001+y;
}
int find(int x,int y)
{
    if(vis[x][y]==1)
        return 0;
    vis[x][y]=1;
    cal[1]=getpos(x,y);
    int cnt=1;
    for(int i = 1, j = 2; i < j; i++)
    {
        int nx = cal[i] / 1001, ny = cal[i] % 1001;
        if(check(nx, ny + 1) && !row[nx][ny] && !vis[nx][ny + 1])
        {
            vis[nx][ny + 1] = 1;
            cal[j++] = getpos(nx, ny + 1);
            ++cnt;
        }
        if(check(nx, ny - 1) && !row[nx][ny - 1] && !vis[nx][ny - 1])
        {
            vis[nx][ny - 1] = 1;
            cal[j++] = getpos(nx, ny - 1);
            ++cnt;
        }
        if(check(nx + 1, ny) && !col[nx][ny] && !vis[nx + 1][ny])
        {
            vis[nx + 1][ny] = 1;
            cal[j++] = getpos(nx + 1, ny);
            ++cnt;
        }
        if(check(nx - 1, ny) && !col[nx - 1][ny] && !vis[nx - 1][ny])
        {
            vis[nx - 1][ny] = 1;
            cal[j++] = getpos(nx - 1, ny);
            ++cnt;
        }
    }
    return cnt;
}
signed main()
{
    int i,j;
    cin>>n;
    int u,v;
    for(i=1;i<=n+1;i++)
    {
        cin>>point[i].x>>point[i].y;
    }
    for(i=1;i<=n;i++)
    {
        if(point[i].x==point[i+1].x)
        {
            int xy=min(point[i].y,point[i+1].y)+1;
            int dy=max(point[i].y,point[i+1].y);
            for(j=xy;j<=dy;j++)
                col[point[i].x][j]=1;
        }
        else
        {
            int xx=min(point[i].x,point[i+1].x)+1;
            int dx=max(point[i].x,point[i+1].x);
            for(j=xx;j<=dx;j++)
                row[j][point[i].y]=1;
        }
    }
    int ans=0;
    find(1,1);
    for(int i = 1; i <= 1000; i++)
    {
        for(int j = 1; j <= 1000; j++) 
            ans = max(ans, find(i, j));
    }
    cout << ans << endl;



    system("pause");
    return 0;
}

N Numbers on both Sides

题意

N张牌。每张牌上都写着两个数字:一个在正面,另一个在背面。你的朋友向你挑战。他把牌洗牌后放在桌上,正面朝上。从左到右,第i张卡片正面的数字是ai,背面的数字是bi。

比赛分为两部分。在第一部分中,从一副牌中选出K张牌。要选一张牌,你必须选择左边的第一张牌,或右边的第一张牌,然后把它拿走。在那之后,你必须从你选择的牌中选择L张并翻转它们。

你的分数将等于写在你所选的所有K牌正面的数字之和,加上写在你所掷的L牌背面的数字之和。求最高得分。

思路

主席树模板

(20条消息) 【Notes】【主席树】hdu2665 Kth number_bestFy的博客-CSDN博客

模板:

#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
int n,m,shu;
const int N=200020;
int a[N],b[N],t[N];
//t[i]表示数组a中每个元素的节点
int sum[N<<5],L[N<<5],R[N<<5];
//sum[i]每个节点包含多少个元素
int l,r,k;
int cnt=0;
/*如题,给定n个整数构成的序列a,将对于指定的闭区间[l,r] 
查询其区间内的第k小值。
输入格式
第一行包含两个整数,分别表示序列的长度 n 和查询的个数 m。
第二行包含 n 个整数,第 i个整数表示序列的第 i 个元素 ai 
接下来 m 行每行包含三个整数 l,r,k , 
表示查询区间[l,r] 内的第 k 小值。*/
int build(int l,int r)
{
    int rt=cnt++;
    sum[rt]=0;
    if(l<r)
    {
        int mid=(l+r)/2;
        L[rt]=build(l,mid);
        R[rt]=build(mid+1,r);
    }
    return rt;
}
int update(int pre,int l,int r,int x)
{
    int rt=++cnt;
    L[rt]=L[pre];
    R[rt]=R[pre];
    sum[rt]=sum[pre]+1;
    if(l<r)
    {
        int mid=(l+r)/2;
        if(x<=mid)
            L[rt]=update(L[pre],l,mid,x);
        else
            R[rt]=update(R[pre],mid+1,r,x);
    }
    return rt;
}
int query(int u,int v,int l,int r,int k)
{
    if(l>=r)
        return l;
    int x=sum[L[v]]-sum[L[u]];
    int mid=(l+r)/2;
    if(x>=k)
        return query(L[u],L[v],l,mid,k);
    else
        return query(R[u],R[v],mid+1,r,k-x);
}
signed main()
{
    IOS ;
    cin>>n>>m;
    int i,j;
    for(i=1;i<=n;i++)
    {
        cin>>a[i];
        b[i]=a[i];
    }
    sort(b+1,b+1+n);
    shu=unique(b+1,b+n+1)-b-1;
    t[0]=build(1,shu);
    for(i=1;i<=n;i++)
    {
        int tt=lower_bound(b+1,b+1+shu,a[i])-b;
        t[i]=update(t[i-1],1,shu,tt);
    }
    while(m--)
    {
        cin>>l>>r>>k;
        int tt=query(t[l-1],t[r],1,shu,k);
        cout<<b[tt]<<endl;
    }



    system("pause");
    return 0;
}

 代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值