ACM-ICPC国际大学生程序设计竞赛北京赛区(2017)网络赛

本文精选了若干比赛编程题目并提供了详细的解题思路与代码实现,包括数字访问问题、小球运动路径计数及线段树应用等。通过具体实例展示了如何使用暴力枚举、数学推导与数据结构优化来解决复杂问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接


01:http://hihocoder.com/problemset/problem/1578
02:http://hihocoder.com/problemset/problem/1579
03:http://hihocoder.com/problemset/problem/1580
04:http://hihocoder.com/problemset/problem/1581
05:http://hihocoder.com/problemset/problem/1582
06:http://hihocoder.com/problemset/problem/1583
07:http://hihocoder.com/problemset/problem/1584
08:http://hihocoder.com/problemset/problem/1585
09:http://hihocoder.com/problemset/problem/1586
10:http://hihocoder.com/problemset/problem/1587
这场比赛感觉自己一直在躺,划水,队友干出三道题唉。。

一些题解


01 Visiting Peking University

 题意是说给定你一串数字,再给定你每个数字能否访问的状态,那么需要在这串数字里选定k个数而这k个数里正好需要有m个是可以访问的,而剩下的是不能访问的。然后在从你选定的这m个里面选择除了第一个的一个位置使第一个位置所代表的数和你选择的位置所代表的数的和最大。
 队友直接暴力,枚举头部然后向后扩展m个可获得的值,取最大即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=1e7+10;
const int INF=0x3f3f3f3f;
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        int x[210];
        bool flag[210];
        memset(flag,0,sizeof(flag));
        for(int i=1;i<=n;i++)
            scanf("%d",&x[i-1]);
        int q,p;
        scanf("%d",&q);
        for(int i=1;i<=q;i++)
        {
            scanf("%d",&p);
            flag[p]=1;
        }
        int ans=INF;
        int now=0;
        int mi=INF;
        int s,e;
        int anss,anse,ansee;
        for(int i=0;i<n;i++)
        {
            if(flag[i]==0)
            {
                 s=i,e=i,mi=INF;
                int cnt=1;
                while(cnt<m)
                {
                    e++;
                    if(e>=n) break;
                    if(flag[e]==0)
                    {
                        cnt++;
                        if(x[e]<mi)
                        {
                            mi=x[e],anse=e;
                        }
                    }
                }
                if(e>=n) break;
                now=mi+x[s];
                //cout<<s<<" "<<anse<<" "<<now<<endl;
                if(now<ans)
                {
                    ans=now;
                    anss=s;
                    ansee=anse;
                }
            }
        }
        printf("%d %d\n",anss,ansee);
    }
    return 0;
}

07 Bounce

 题意是说给定一个n*m的区域,有一个小球从左上出发方向是正斜向右下,如果进入四个角则停止,如果遇到边就按反射角反弹。问你有几个格子经过且经过一次。
 队友推的公式orz, a + b - a * b - gcd(m, n)。其中a是n / gcd(n, m),b是m / gcd(n, m)。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll lcm(ll a,ll b)
{return a/__gcd(a,b)*b;}
ll solve(ll a,ll b) {return a+b-a*b;}
int main()
{
    ll n,m;
    while(scanf("%lld%lld",&n,&m) != EOF)
    {
        if(2*n-1==m)
        {
            printf("%lld\n",m);
            continue;
        }
        if(n==m)
        {
            printf("%lld\n",n);
            continue;
        }
        ll gcd = __gcd(--n,--m);
        ll ans = lcm(n,m)+solve(n/gcd,m/gcd);
        printf("%lld\n",ans);
    }
    return 0;
}

09 Minimum

 简单的线段树单点更新。

//线段树单点更新+RMQ
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=200005;
const ll inf = 0x3f3f3f3f;
#define lson (i<<1)
#define rson (i<<1|1)
struct {
    ll l,r,MAX,MIN;
}tree[4*maxn];
void maintain(ll i)
{
    tree[i].MAX=max(tree[lson].MAX,tree[rson].MAX);
    tree[i].MIN=min(tree[lson].MIN,tree[rson].MIN);
}
void build(ll i,ll L,ll R)
{
    tree[i].l=L,tree[i].r=R;
    tree[i].MAX=tree[i].MIN=0;
    if(L==R)
    {
        ll tmp;scanf("%lld",&tmp);
        tree[i].MAX=tree[i].MIN=tmp;
        return;
    }
    ll M=(L+R)>>1;
    build(lson,L,M);
    build(rson,M+1,R);
    maintain(i);
}
void update(ll i,ll p,ll v)
{
    ll L=tree[i].l,R=tree[i].r;
    ll M=(L+R)>>1;
    if(L==R && L==p)
    {
        tree[i].MAX=tree[i].MIN=v;
        return;
    }
    if(M>=p)update(lson,p,v);
    else update(rson,p,v);
    maintain(i);
}
ll queryMIN(ll i,ll l,ll r)
{
    ll L=tree[i].l,R=tree[i].r;
    if(l<=L && R<=r)
        return tree[i].MIN;
    ll M=(L+R)>>1,_min=inf;
    if(M<r) _min=queryMIN(rson,l,r);
    if(M>=l) _min=min(_min,queryMIN(lson,l,r));
    return _min;
}

ll queryMAX(ll i,ll l,ll r)
{
    ll L=tree[i].l,R=tree[i].r;
    if(l<=L && R<=r) return tree[i].MAX;
    ll M=(L+R)>>1,_max=-inf;
    if(M<r) _max=queryMAX(rson,l,r);
    if(M>=l) _max=max(_max,queryMAX(lson,l,r));
    return _max;
}
int main()
{
    ll m,t;
    scanf("%lld",&t);
    while(t--)
    {
        scanf("%lld",&m);m=(1<<m);
        build(1,1,m);
        ll q;scanf("%lld",&q);
        while(q--)
        {
            ll op;scanf("%lld",&op);
            ll x,y;scanf("%lld%lld",&x,&y);
            if(op==2)
                update(1,++x,y);
            if(op==1)
            {
                x++;y++;
                ll aa = queryMAX(1,x,y);
                ll bb = queryMIN(1,x,y);
                printf("%lld\n",min(min(aa*bb,aa*aa),bb*bb));
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值