Technocup 2020 - Elimination Round 1补题

慢慢来。

题目册

题目 A B C D
tag math strings greedy dp
状态

//∅,√,×


想法

A. CME

res tp A
题意:有\(n\)根火柴,额外填上\(k(k≥0)\)根火柴棍,使得\(n+k\)能分成三份\(a,b,c\),每份至少有一根火柴,满足\(a+b = c\),问\(k\)最小是多少
满足方程
\(a+b+c = n+k\)
\(a + b = c\)
\(2*c = n+k\)
\(n\)是偶数,那么\(k\)为零,反之\(k\)\(1\)
特别地,\(n\)至少要为\(4\),才能凑出一个等式\(1+1=2\)

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i = (a);i>=(b);--i)
#define fo(i,a,b) for(int i =(a);i<(b);++i)
#define de(x) cout<<#x<<" = "<<x<<endl;
#define endl '\n'
#define mem(a,b) memset(a,b,sizeof(a));
#define ls(p) ((p)<<1)
#define rs(p) (((p)<<1)|1)
using namespace std;
typedef long long ll;
const int mn = 105;

int n,q;
int main(){
    cin>>q;
    while(q--){
        cin>>n;
        if(n < 4)
            cout<<4 - n<<endl;
        else
            cout<< (n&1) <<endl;
    }
}

B. Strings Equalization

res tp B
题意:给出两个仅包含小写字母的字符串,问是否存在某个字符在两串中都出现过

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i = (a);i>=(b);--i)
#define fo(i,a,b) for(int i =(a);i<(b);++i)
#define de(x) cout<<#x<<" = "<<x<<endl;
#define endl '\n'
#define mem(a,b) memset(a,b,sizeof(a));
#define ls(p) ((p)<<1)
#define rs(p) (((p)<<1)|1)
using namespace std;
typedef long long ll;
const int mn = 105;


char s[mn],t[mn];
int q,m;
bool vis[27],ans;
int main(){
    cin>>q;
    while(q--){
        cin>>s>>t;
        ans = 0;
        mem(vis,0);
        m =strlen(s);
        rep(i,0,m-1)    vis[ s[i]-'a' ] = 1;
        rep(i,0,m-1) if(vis[t[i]-'a']){
            ans = 1;break;
        }
        if(ans) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
}


C. Save the Nature

res tp C
题意:给定一个整数序列\(p_i,i\in[1,n]\),你可以对其进行打乱顺序重新排列。定义了一个规则,下标是\(a\)的倍数的,可以有\(x%\)的贡献,下标是\(b\)的倍数的,可以有\(y%\)的贡献,问,在重排之后,按上述规则,从\(1\)开始,最少需要多少个连续的数,使得总贡献不小于\(k\)
贪心地考虑,下标若既是\(a\)的倍数,又是\(b\)的倍数,那岂不是能贡献两份吗?我们先按从大到小的顺序钦定这类下标的元素值,之后再依照\(x\)\(y\)的大小关系继续钦定剩下的对答案有贡献的位置,遍历区间\([1,i]\),执行上述操作,直到遇到第一个总贡献不小于\(k\)的下标,而那就是我们想要得到的最终答案。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i = (a);i>=(b);--i)
#define fo(i,a,b) for(int i =(a);i<(b);++i)
#define de(x) cout<<#x<<" = "<<x<<endl;
#define endl '\n'
#define ls(p) ((p)<<1)
#define rs(p) (((p)<<1)|1)
using namespace std;
typedef long long ll;
const int mn = 2e5+10;
int n, q, na, nb, nc, x, y, a, b;
ll p[mn], k;
bool cmp1(ll a,ll b){return a>b;}
int ans;
inline ll gcd(ll x,ll y){
    return (y == 0? x:gcd(y,x%y));
}
inline ll solve(int num){
    na = num/a;nb = num/b;
    nc = na&&nb?num/(a/gcd(a,b)*b):0; nb-=nc;na-=nc;
    ll res = 0;
    res += (p[nc] - p[0])*(x+y);
    if(x > y){
        res += (p[nc + na]- p[nc])*x;
        res += (p[nc + na + nb] - p[nc + na])*y;
    }
    else{
        res += (p[nc + nb] - p[nc])*y;
        res += (p[nc + na + nb] - p[nc + nb])*x;
    }
    return res/100;
}

int main(){
    scanf("%d",&q);
    while(q--){
        scanf("%d",&n);
        rep(i,1,n) cin>>p[i];
        sort(p+1,p+1+n,cmp1);
        rep(i,1,n) p[i] += p[i-1];
        scanf("%d%d%d%d",&x,&a,&y,&b);
        scanf("%lld",&k);
        ans = -1;
        rep(i,1,n)  if( solve(i) >=k ){
            ans = i;
            break;
        }
        printf("%d\n",ans);
    }
}

D. Sequence Sorting

res tp D
题意:给定一个序列,可以进行进行一种操作:选定一个x,之后将值为x的所有数字移动到序列的最左端或最右端,问最少进行多少次操作,使得序列满足单调不减

首先取出原序列中我们需要的信息,而其他的信息可以忽略。求出其每种元素的两个特征:初次出现位置和末次出现位置。
按元素值从小到大的序列就是我们最终要得到的序列。为了让操作数尽可能小,我们需要省去一些力气。如果原序列和终序列在某些地方是“相似”的,岂不是可以省去对这部分“相似”的操作吗?
具体地说,对终序列的两个数值紧邻的元素,若他们的分布区间不相交,且保证较小的元素的区间在较大的元素的左侧,那么这两种元素的相对位置在两个序列中是相等的,也就是说,它们对操作数没有贡献。
反之,至少要对其中的一个元素进行操作,同时,这也意味着,被操作元素那一侧的所有元素都要被操作。
综上,不需要操作的元素一定在终序列中是连续,于是可以dp出终序列满足条件的最长子区间,再用元素种类数减之即为答案

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i = (a);i>=(b);--i)
#define fo(i,a,b) for(int i =(a);i<(b);++i)
#define de(x) cout<<#x<<" = "<<x<<endl;
#define endl '\n'
#define mem(a,b) memset(a,b,sizeof(a));
#define ls(p) ((p)<<1)
#define rs(p) (((p)<<1)|1)
using namespace std;
typedef long long ll;
const int mn = 3e5+10;
int q,n;
struct E{
    int v,l,r;
}e[mn];
int vis[mn],t,cnt,mdp,dp;
bool cmp(E a,E b){return a.v <b.v;}
int main(){
    scanf("%d",&q);
    while(q--){
        cnt = 1;
        scanf("%d",&n);
        rep(i,1,n){
            scanf("%d",&t);
            if(vis[t])
                e[vis[t]].r = i;
            else{
                e[cnt].l = e[cnt].r = i;
                e[cnt].v = t;
                vis[t] = cnt++;
            }
        }
        sort(e+1,e+cnt,cmp);
        mdp = dp = 1;
        int cnt1 = cnt - 1;
        rep(i,2,cnt1){
            if(e[i-1].r <e[i].l) ++dp;
            else dp = 1;
            mdp = max(mdp,dp);
        }
        printf("%d\n",cnt - 1 - mdp);
        rep(i,1,cnt1) vis[e[i].v] = 0;
    }
}

猜你喜欢

转载自www.cnblogs.com/tea-egg/p/11644875.html