2019ICPC徐州网络赛

25 篇文章 0 订阅

B. so easy

theme:n个数编号为1~n,两种操作:1 x:将编号为x的数置为不可得,2 x:询问x位置及其后第一个可得数的编号。1<=n,x<1e9,1<=q<1e6

solution:首先想到用线段树维护。初始时线段树每个l==r位置的值为l,1 x操作对应将x位置值置为inf,2 x 操作相当于查询区间[x,n]的最小值。由于n很大,所以要离散化。可以记录下所有操作的x值,进vector,并把x+1也作为节点,这样的话查询[x,n]就保证一定正确了

#include<bits/stdc++.h>
#include<vector>
#include<algorithm>
using namespace std;
#define far(i,t,n) for(int i=t;i<n;++i)
#define pk(a) push_back(a)
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
int inf=0x3f3f3f3f;
struct _a
{
    int z,x;
}a[1000010];
vector<int>v;
int tree[2000020<<2];

void push_up(int rt)
{
    tree[rt]=min(tree[rt<<1],tree[rt<<1|1]);
}

void build(int rt,int l,int r)
{
    if(l==r)
    {
        tree[rt]=v[l-1];
        return;
    }
    int mid=(l+r)>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    push_up(rt);
}

void update(int rt,int l,int r,int pos)
{
    if(l==r)
    {
        tree[rt]=inf;
        return;
    }
    int mid=(l+r)>>1;
    if(pos<=mid)
        update(rt<<1,l,mid,pos);
    else
        update(rt<<1|1,mid+1,r,pos);
    push_up(rt);
}

int query(int rt,int l,int r,int L,int R)
{
    if(L<=l&&r<=R)
        return tree[rt];
    int mid=(l+r)>>1;
    int ans=inf;
    if(L<=mid)
        ans=min(ans,query(rt<<1,l,mid,L,R));
    if(R>mid)
        ans=min(ans,query(rt<<1|1,mid+1,r,L,R));
    return ans;
}

int main()
{
    int n,q;
    cin>>n>>q;
    far(i,0,q)
    {
        scanf("%d%d",&a[i].z,&a[i].x);
        v.push_back(a[i].x);
        v.push_back(a[i].x+1);
    }
    sort(v.begin(),v.end());
    int sz=unique(v.begin(),v.end())-v.begin();
    build(1,1,sz);
    far(i,0,q)
    {
        int pos=lower_bound(v.begin(),v.begin()+sz,a[i].x)-v.begin()+1;
        if(a[i].z==1)
            update(1,1,sz,pos);
        else
        {
            int ans=query(1,1,sz,pos,sz);
            printf("%d\n",ans);
        }
    }
}

G. Colorful String

M. Longest subsequence

K. Center

theme:给定n个二维平面上的点,问至少添加几个点可以使得有这些点组成的图形是中心对称图形(对称中心任意)。1<=n<=1000,-1e6<=x,y<=1e6

solution:如果一个图形是中心对称图形,则对称中心是某些点对的中点。n范围较小,我们可以枚举出每个点与任意其他点的中点)(只要有一个点不同,则中点肯定不同),看哪个点是最多点对的中点。实现的话可以放在map里,再求map最大值。由于某个点自己也可能是对称中心,所以枚举i,i时对答案的贡献+1,其他情况+2表示这两个点都不需要给它加点,结果就为n-ans.注意特判n=1

#include<bits/stdc++.h>
#include<vector>
#include<algorithm>
using namespace std;
#define far(i,t,n) for(int i=t;i<n;++i)
#define pk(a) push_back(a)
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
int inf=0x3f3f3f3f;

struct _a
{
    int x,y;
    _a(){}
    _a(int a,int b)
    {
        x=a;
        y=b;
    }
    bool operator<(_a b)const
    {
        if(x==b.x)
            return y<b.y;
        return x<b.x;
    }
    bool operator==(_a b)const
    {
        return x==b.x&&y==b.y;
    }
}a[1010];
map<_a,int>um;
map<_a,int>::iterator it;
int main()
{
    int n;
    cin>>n;
    far(i,0,n)
        scanf("%d%d",&a[i].x,&a[i].y);
    if(1==n)
    {
        cout<<0<<endl;
        return 0;
    }
    sort(a,a+n);
    n=unique(a,a+n)-a;
    far(i,0,n)
        far(j,i,n)
        {
            _a b;
            b.x=a[i].x+a[j].x;
            b.y=a[i].y+a[j].y;
            if(i!=j)
                um[b]+=2;
            else
                um[b]++;
            //cout<<b.x<<" "<<b.y<<" "<<um[b]<<endl;
        }
    int ans=0;
    for(it=um.begin();it!=um.end();++it)
        ans=max(ans,it->second);
    cout<<n-ans<<endl;
}

E. XKC's basketball team

theme:给定长度为n的数组,给定m,对于数组中的每个数,求ai右边比ai+m大的最远(下标距离最大)的数与ai之间有几个数,没有比ai+m的大的输出-1。2<=n<=5e5,0<=m,ai<=1e9

solution:由题意只该题就是求每个元素右边>=ai+m的最远的下标。可以借助线段树每次优先往右边搜最大值。

有一种更简便的方法:将ai从小到大排序,则对于每一个ai找到>=ai+m的第一个位置,则排序后[pos,n]里所有的元素都满足要求,这时我们只需找到[pos,n]里的元素中下标的最大值即可。而用结构体记录下标和值后,排好序后用dp就可以很容易求出后缀最大值(对于下标)。注意当m=0时由于不能选到自己,此时就不要lower_bound()找pos,直接pos=i+1

#include<bits/stdc++.h>
#include<vector>
#include<algorithm>
using namespace std;
#define far(i,t,n) for(int i=t;i<n;++i)
#define pk(a) push_back(a)
typedef long long ll;
typedef unsigned long long ull;
using namespace std;

struct _a
{
    int idx;
    ll w;
    bool operator<(const _a b)const
    {
        return w<b.w;
    }
}a[500050];

int rmax[500050];
int ans[500050];

int main()
{
    int n,m;
    cin>>n>>m;
    far(i,0,n)
        scanf("%lld",&a[i].w),a[i].idx=i;
    sort(a,a+n);
    rmax[n]=-1;
    for(int i=n-1;i>=0;--i)
        rmax[i]=max(rmax[i+1],a[i].idx);
    far(i,0,n)
    {
        int pos;
        _a x;
        x.w=a[i].w+m;
        if(0==m)
            pos=i+1;
        else
            pos=lower_bound(a,a+n,x)-a;
        ans[a[i].idx]=rmax[pos]>a[i].idx?rmax[pos]-a[i].idx-1:-1;
    }
    printf("%d",ans[0]);
    far(i,1,n)
        printf(" %d",ans[i]);
    puts("");
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值