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;
}