训练赛2(小)

导语

小型训练赛,虽然不用交整理,但是自己还是想整理一下,毕竟题目简单都没做完

涉及的知识点

贪心、思维、字符串、树、差分

链接:ACM2019 weekly - 1

题目

A(CodeForces 996A)

题目大意:给出一个数,尝试用1,5,10,20,100的硬币并且用最少的个数分完

思路:贪心,每次用面值最大的分到不能分为止,换更小的一个

代码

#include <bits/stdc++.h>
using namespace std;
long long n,data[5]= {1,5,10,20,100},ans;
int main() {
    cin >>n;
    for(int i=4; i>=0; i--)
        if(n) {
            ans+=n/data[i];
            n%=data[i];
        }
    cout <<ans;
    return 0;
}

B(CodeForces 991A)

题目大意:A个学生去过1地,B个学生去过2地,C个学生两地都去过,N为学生总个数,没有去过1地和2地的至少有一人,判断给出的数是否满足这样的条件

思路:直接用集合论判断,注意特殊情况,比如C ≥ \ge A或C ≥ \ge B

代码

#include <bits/stdc++.h>
using namespace std;
int A,B,C,N,pass;
int main() {
    cin >>A>>B>>C>>N;
    N-A-B+C>=1&&C<=A&&C<=B?cout <<N-A-B+C:cout <<"-1";
    return 0;
}

C(CodeForces 989B)

题目大意:给出一个由0、1、.构成的字符串,给出串的长度n和一个数p,.可以被替换成0或1,当对所有的1 ≤ \le i ≤ \le n-p,第i个和第i+p个字符如果都相等则认为该字符串为p字符串,对于给定的0、1、.构成的字符串,判断能否组成为p字符串

思路:直接模拟即可,注意判断如果一开始所有i和i+p都相等了,就不可能有非p字符串

代码

#include <bits/stdc++.h>
using namespace std;
int n,p,ans;
char str[2121];
bool flag;
int main() {
    scanf("%d%d",&n,&p);
    getchar();
    scanf("%s",str+1);
    for(int i=1; i<=n-p; i++)
        if(str[i]==str[i+p]) {//找到了直接变
            if(str[i]=='.') {
                str[i]='1',str[i+p]='0';
                flag=1;
                break;
            }
        } else {
            if(str[i]=='.') {
                if(str[i+p]=='1')
                    str[i]='0';
                else if(str[i+p]=='0')
                    str[i]='1';
            } else if(str[i+p]=='.') {
                if(str[i]=='1')
                    str[i+p]='0';
                else if(str[i]=='0')
                    str[i+p]='1';
            }//能变直接变,只需要有一对地方不同即可
            flag=1;
            break;
        }
    if(!flag)
        cout <<"No";
    else
        for(int i=1; i<=n; i++)
            if(str[i]=='.')
                printf("1");
            else
                printf("%c",str[i]);
    return 0;
}

D(CodeForces 978E)

题目大意:有一辆公交车,经过n个站,给出最大容量w,给出每个站公交车上数量相对于前一个站的公交车数量的变化值,求出最开始公交车上的人数有多少种可能

思路:贪心,获取可能人数的最大上限和最小下限,相减即是答案,注意排除特殊情况

代码

#include <bits/stdc++.h>
using namespace std;
long long n,w,a[1212],H,L,ans;
bool flag;
int main() {
    scanf("%lld%lld",&n,&w);
    H=w;
    for(int i=1; i<=n; i++)
        scanf("%lld",&a[i]);
    for(int i=1; i<=n; i++) {
        ans+=a[i];
        if(ans>0)
            H=min(H,w-ans);//取最大上界
        else if(ans<0)
            L=max(L,-ans);//取最小下界
    }
    printf("%lld",H-L+1>0?H-L+1:0);//特判情况
    return 0;

E(CodeForces 982C)

题目大意:给出一棵树,如果去掉一条边可以分成两个有偶数个点的连通块(子树)就可以去掉这条边,问最多能去掉几条边

思路:当树的节点个数为奇数个显然没有答案,当树的节点数为偶数的时候,以顶点1为父节点开始dfs计算子树的顶点个数,如果子树+1(该点)为偶数个顶点,代表去掉该点与其父节点的边必然能产生两个有偶数个点的连通块,去掉该边,计数,标记该子树,最后答案需-1,因为整棵树顶点为偶数个(不切也被计算了)
在本题中可以以任意一个点开始搜索,因为是一个连通图,并且没有硬性规定谁是树根或叶子节点

代码

#include <bits/stdc++.h>
using namespace std;
int n,u,v,cnt;
bool visit[121212];
vector<int>Tree[121212];
int DFS(int x) {
    int ans=0;
    visit[x]=1;
    for(int i=0;i<Tree[x].size();i++)
        if(!visit[Tree[x][i]])
            ans+=DFS(Tree[x][i]);
    if((ans+1)%2==0)//该点与其子树的和为偶数
        cnt++;
    return ans+1;
}
int main() {
    scanf("%d",&n);
    for(int i=0;i<n-1;i++) {
        scanf("%d%d",&u,&v);
        Tree[u].push_back(v);
        Tree[v].push_back(u);//存树
    }
    if(n&1)
        printf("-1");
    else {
        DFS(1);
        printf("%d",cnt-1);
    }
    return 0;
}

F(CodeForces 1000C)

题目大意:给出n条线段以及每条线段的起始点和终止点,问被k条线段覆盖的点的个数,k从1到n

思路:由于数据量过大,因此开一个数组进行差分累和不现实,只能采用离散化的方法进行差分,具体看代码

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,data[212121],last,ans;//ans代表差分中的累和变量
map<ll,ll>M;
map<ll,ll>::iterator p;
int main() {
    scanf("%lld",&n);
    for(int i=0; i<n; i++) {
        ll l,r;
        scanf("%lld%lld",&l,&r);
        M[l]++,M[r+1]--;//差分思想
    }
    for(p=M.begin(); p!=M.end(); p++) {//遍历区间
        if(p==M.begin()) {
            last=p->first;//区间起点
            ans+=p->second;//起点线段覆盖数
            continue;
        }
        data[ans]+=p->first-last;//记录覆盖数对应点数
        last=p->first;
        ans+=p->second;//控制覆盖数的大小
    }
    for(int i=1; i<=n; i++)
        cout <<data[i]<<(i==n?"\n":" ");
    return 0;
}

参考文献

  1. CodeForces ~ 982C ~ Cut 'em all! (树 + dfs)
  2. 1000C. Covered Points Count(线段覆盖问题)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值