2018-2019 ICPC, NEERC, Northern Eurasia Finals 一些题解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lingzidong/article/details/84800025

Easy Chess
队友牛逼构造了一下,好像还有更简单的代码

#include <bits/stdc++.h>
#include <cstring>
using namespace std;
const int MOD=1e9+7;
const int INF=0x3f3f3f3f;
string ans[70]= {"b1","c1","d1","e1","f1","g1","h1",
                 "h2","g2","f2","e2","d2","c2","b2","a2",
                 "a3","b3","c3","d3","e3","f3","g3","h3",
                 "h4","g4","f4","e4","d4","c4","b4","a4",
                 "a5","b5","c5","d5","e5","f5","g5","h5",
                 "h6","h7","g7","g6","f6","f7","e7","e6",
                 "d6","d7","c7","c6","b6","b7","a7","a6",
                 "a8","b8","c8","d8","e8","f8","g8","h8"
                };

int main()
{
    int n;
    scanf("%d",&n);
    n--;
    cout<<"a1"<<' ';
    if(n==1)
        cout<<"a8"<<' '<<"h8"<<endl;
    else if(n==56||n==57||n==58||n==59||n==60||n==61||n==62||n==7||n==8||n==23||n==24||n==39||n==40||n==41)
    {
        for(int i=0; i<n; i++)
        {
            cout<<ans[i]<<' ';
        }
        cout<<"h8"<<endl;
    }
    else if(n-1==41)
    {
        for(int i=0; i<n-2; i++)
            cout<<ans[i]<<' ';
        cout<<"g6"<<' '<<"g8"<<' '<<"h8"<<endl;
    }

    else if(n-1==8||n-1==23||n-1==24||n-1==39||n-1==40)
    {
        for(int i=0; i<n-1; i++)
            cout<<ans[i]<<' ';
        cout<<ans[n-2][0]<<(char)(ans[n-2][1]+1)<<' '<<"h8"<<endl;
    }
    else
    {
        for(int i=0; i<n-1; i++)
        {
            cout<<ans[i]<<' ';
        }
        cout<<ans[n-2][0]<<8<<' '<<"h8"<<endl;
    }
    return 0;
}

L. Lazyland
简单贪心,如果一个任务有人选的话就选b最大的,剩下的人按照b从小到大排就行

#include <bits/stdc++.h>
#include <cstring>
using namespace std;
const int MOD=1e9+7;
const int INF=0x3f3f3f3f;
vector<int> arr[100005];
vector<int> brr;
int mp[100005];

int main()
{
    int n,k;
    int len;
    scanf("%d%d",&n,&k);
    int a,b;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&mp[i]);
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a);
        arr[mp[i]].push_back(a);
    }
    for(int i=1;i<=k;i++)
        if(!arr[i].empty())
            sort(arr[i].begin(),arr[i].end());
    for(int i=1;i<=k;i++)
    {
        if(!arr[i].empty())
        {
            len=arr[i].size();
            for(int j=0;j<len-1;j++)
            {
                brr.push_back(arr[i][j]);
            }
        }
    }
    long long ans=0;
    sort(brr.begin(),brr.end());
    len=brr.size();
    for(int i=0;i<len-(n-k);i++)
    {
        //cout<<brr[i]<<endl;
        ans+=1ll*brr[i];
    }
    printf("%lld\n",ans);
    return 0;
}

G. Guest Student
枚举一下最后几天(不满一周的情况)从那一天开始用时最短就行。

Copy
#include <bits/stdc++.h>
#include <cstring>
using namespace std;
const int MOD=1e9+7;
const int INF=0x3f3f3f3f;
int arr[10];

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int k;
        scanf("%d",&k);
        int sum=0;
        for(int i=0;i<7;i++)
            scanf("%d",&arr[i]),sum+=arr[i];
        int tims=k/sum;
        int ans=0;
        int en=k%sum;
        if(k%sum==0)
            tims--,en=sum;
        int MIN=INF;
        for(int i=0;i<7;i++)
        {
            ans=0;
            for(int j=0;j<7;j++)
            {
                ans+=arr[(i+j)%7];
                if(ans==en)
                    MIN=min(j,MIN);
            }
        }
        printf("%d\n",7*tims+MIN+1);
    }
    return 0;
}

F. Fractions
本来是打算搜一下,但是试着构造了几个。发现不敢怎么样都只有两个数的情况,于是踩了一个只要能被构造出来,就一定能被两个数构造出来。
首先从n的所有因子中从大到小枚举作为第一个数的分母,之后枚举这个数的分子,判断一下剩下的值能不能被约分。

#include <bits/stdc++.h>
using namespace std;
vector<int> fac;
int main()
{
    int n;
    cin>>n;
    for(int i = 2; i*i<n; i++)
    {
        if(n % i == 0)
            fac.push_back(i);
    }
    int sz = fac.size();
    for(int i = sz-1;i>=0;i--)
    {
        int it = fac[i];
        int a = n/it;
        for(int i = 1; i*a<n-1; i++)
        {
            int rem = n-1-i*a;
            if(rem <= 0) break;
            if(__gcd(n,rem) != 1)
            {
                //if((n/__gcd(n,rem) == 1)) continue;
                cout<<"YES"<<endl;
                cout<<2<<endl;
                cout<<i<<' '<<it<<'\n'<<rem/__gcd(rem,n)<<' '<<n/__gcd(n,rem)<<endl;
                return 0;
            }
        }
    }
    cout<<"NO"<<endl;
    return 0;
}

K - King Kog’s Reception
给出添加删除操作,求出某个时刻等待的时间,三个操作。
一开始以为要可持续化一下,后来发现根本上是不用的。
我们首先用线段树维护某个时间点最长延伸到的时间,用来维护某个询问时间节点前面需要等待的时间。
题目中要求如果有的插入操作于询问时间一致,需要再等。我们再用一个树状数组维护一下这个时间节点同时来的要等多长时间,是个求和,因为每个人都要等,要注意其他人前面等的时间都是一样的,所以这个关系是成立的。最后减一减就行了。

这个题让我想到一般思考一个数据结构题的过程,我试着写写: 首先确定是什么问题,如果是区间问题:
如果涉及到区间位置更改,就是splay或者treap问题 如果涉及到区间的各种更新等等,就是线段树各种搞,如果一棵树搞不定,就用两颗。
如果涉及到求区间kth,就上主席树吧。
由于合并掌握的不是很熟练,反正也做不出来就不写了。
如果是树上问题:
判断可不可以用求dfs序的方式求解,这样的问题可以用树链剖分或者上个线段树解决(差不多)。
判断是不是要求改变节点位置,如果是的话,就是LCT了。 其他的虚树好像不会的样子,可以开别的题了。 如果查询可以离线:
如果查询区间满足莫队算法的更新,那么可以用莫队,但是要注意数据范围。
总之嘛,首先要对数据结构本身了解透彻,之后要认真分析,一层一层的解析,不能上来就下判断……

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN = 3e5 + 5;
const int MAX = 1e6 + 5;
const int INF = 0x3f3f3f3f;
struct Record
{
    int t,d;
}rec[MAXN];
int tot;
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,ls
#define rson mid+1,r,rs
ll mx[MAX<<2];
ll tag[MAX<<2];
void push_up(int rt)
{
    mx[rt] = max(mx[ls],mx[rs]);
}
void push_down(int rt,int m)
{
    if(tag[rt])
    {
        tag[ls] += tag[rt];
        tag[rs] += tag[rt];
        mx[ls] += tag[rt];
        mx[rs] += tag[rt];
        tag[rt] = 0;
    }
}
void build(int l,int r,int rt)
{
    mx[rt] = l;
    if(l == r) return ;
    int mid = (l + r) >> 1;
    build(lson);
    build(rson);
    push_up(rt);
}
void update(int L,int R,ll c,int l,int r,int rt)
{
    if(L <=l && r <= R)
    {
        mx[rt] += c;
        tag[rt] += c;
        return ;
    }
    push_down(rt,r - l +1);
    int mid = (l + r) >> 1;
    if(L <= mid) update(L,R,c,lson);
    if(R > mid) update(L,R,c,rson);
    push_up(rt);
}
ll query(int L,int R,int l,int r,int rt)
{
    if(L <=l && r <= R)
    {
        return mx[rt];
    }
    push_down(rt,r - l +1);
    int mid = (l + r) >> 1;
    ll res = 0;
    if(L <= mid) res = max(res,query(L,R,lson));
    if(R >  mid) res = max(query(L,R,rson),res);
    return res;
}
ll sum[MAX];
int lowbit(int x)
{
    return x & (-x);
}
void add(int x,ll c)
{
    while(x <= MAX)
    {
        sum[x] += c;
        x+= lowbit(x);
    }
}
ll ask(int x)
{
    ll res = 0;
    while(x>0)
    {
        res += sum[x];
        x -= lowbit(x);
    }
    return res;
}
int main()
{
    int q;
    scanf("%d",&q);
    build(1,MAX,1);
    while(q--)
    {
        ++tot;
        int t,d;
        char op;
        getchar();
        scanf("%c",&op);
        if(op == '+')
        {
            scanf("%d%d",&t,&d);
            rec[tot].t = t;
            rec[tot].d = d;
            update(1,t,d,1,MAX,1);
            add(t,d);
        }
        else if(op == '-')
        {
            scanf("%d",&t);
            //cout<<rec[t].t<<' '<<rec[t].d<<endl;
            update(1,rec[t].t,-rec[t].d,1,MAX,1);
            add(rec[t].t,-rec[t].d);
        }
        else
        {
            scanf("%d",&t);
            ll ans = query(1,t,1,MAX,1) - t - (ask(MAX) - ask(t));
           // cout<<query(1,t,1,MAX,1)<<endl;
            printf("%lld\n",ans);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lingzidong/article/details/84800025