2021合肥市赛

文章目录



前言

针不戳~



一、小C的计算

题目

小 C 擅长计算,整天都在进行着各种各样的计算。

这不,小 C 又开始了一个计算问题:输入两个数 L、R,输出所有 L 到 R 之间(包括 L、R)的质数的和。

输入格式:

一行两个整数 L、R

输出格式:

一个数

限制:

空间限制:128MByte

时间限制:1秒

样例:

输入:

【测试样例#1输入】 15 23

【测试样例#2输入】 123456789 123457789

输出:

【测试样例#1输出】 59

【测试样例#2输出】 5925949806

提示:

对于 30%的数据, 1 ≤ L≤ R≤ 1000

对于 100%的数据,1 ≤ L≤ R≤ 1e9,R-L≤ 1000

代码

有谁这题想用埃筛的(doge),不要瞧不起暴力好吧

当然,埃筛也不是不可以,但比较麻烦

代码:

#include<iostream>
#include<cmath>
using namespace std;
long long n,m,sum;
bool ss(long long x){
	if(x==1) return false;
	for(long long i=2;i<=sqrt(x);i++)
		if(x%i==0) return false;
	return true;
}
int main(){
	cin>>n>>m;
	for(long long i=n;i<=m;i++)
		if(ss(i)) sum+=i;
	cout<<sum;
	return 0;
}


二、小C的工作


题目

小 C 不喜欢上班。他的老板又给小 C 安排了 n 项任务。老板担心小 C 在公司里不干活儿,于是给每一项任务安排了一个最迟动工时间 ti ,当超过时间 ti 时(不包括 ti这个时间点),如果小 C 仍未动工,就会被扣薪。小 C 可以选择在 ti 时刻之前或者恰好在 ti 时刻办这项任务,一旦选择开始办,就必须连续不断、且时长达到 li 才能完成这项任务。

在任意时刻下,小 C 最多只能做一项任务。小 C 很懒,他想合理安排任务顺序,使得开始办第一项任务的时间尽可能地迟,并且不会被扣薪。请你告诉他最迟的时间。

输入格式:

第一行一个正整数 n,表示任务个数;

接下来 n 行,每行两个整数 ti 和 li ,表示每项任务最迟动工时间以及完成任务所需的

工作时长。

输出格式:

仅一行一个数,表示最迟的工作时间。

限制:

空间限制:128MByte

时间限制:1秒

样例:

输入:

【测试样例#1输入】 2 1 4 2 2

【测试样例#2输入】 5 2 5 3 3 7 4 8 2 10 1

输出:

【测试样例#1输出】 -1

【测试样例#2输出】 -4

提示:

【样例 1 解释】

按照 2、1 的任务顺序,工作的时间区间为 [−1,1][1,5]。显然开始工作的时间不能

迟于时刻 −1。

【样例 2 解释】

按照 2、1、5、4、3 的任务顺序,工作的时间区间为 [−4,−1][−1,4][4,5][5,7][7,11]。

【数据范围】

对于 10% 的数据:n = 2;

对于 30% 的数据:n ≤ 10;

对于 60% 的数据:n ≤ 5 × 1e3;
对于 100% 的数据:n ≤ 2 × 1e5,0 < li ,ti≤ 1e9。


代码

既然是最晚的开始时间,那就是贪心了

而且还得满足不扣薪,那么就应该找他最晚的完成时间

然后一个个往前推就好

推完后得出的开始时间还要与n个任务当中最小的开始时间作比较,如果最小的开始时间比推完后得出的开始时间小时,应选最小的开始时间

代码:

#include<iostream>
using namespace std;
const int N=1e6;
long long x=-1,y=100000000000,n;
struct node{
	long long start1,end1;
}a[N];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i].start1>>a[i].end1;
		x=max(x,a[i].end1+a[i].start1);
		y=min(y,a[i].start1);
	}
	for(int i=1;i<=n;i++) x-=a[i].end1;
	x=min(x,y);
	cout<<x;
	return 0;
}

ps:数组要2e5以上哦

三、小 C 爱观察

题目

小 C 非常喜欢树。上次后院的蚂蚁看腻了,这次准备来观察树。

小 C 每天起得早早的,给小树浇水,并且每天记录这棵小树的一些数据。树在小 C 的精心呵护下不断长大。经过若干天的记录,小 C 竟然发现了一棵树生长的规律!

为了阐述其规律,小 C 想先使用一种严谨的语言来抽象化一棵树。

首先,小 C 用图论的概念定义了一棵树 T =< V,E >,V 表示所有点构成的集合,E 表示所有边(无向边)构成的集合。一棵具有一定形态的树用一个大写字母简记,一般会使用T;其大小等于 |V|,即节点的个数。

小 C 发现所有树都有一个共同点:大小为 n 的树,恰好含有 n − 1 条边,并且任意两个节点间存在路径使得互相可达。比如说下图中 (A) 是一棵树,而 (B)(C) 却不是。

2021合肥市赛


自然界中所有树都有根,对于树 T 也有且仅有一个根,其为 V 中的某个节点 r。于是小 C 可以对所有节点定义深度,节点 u 的深度等于 u 到 r 的距离 +1,例如下面这棵树中,令节点 1 为根 r,则节点 2、3 的深度为 2,节点 4、5 的深度为 3,而节点 1 自身的深度为 1。

2021合肥市赛

由此可以看出,抽象出来的树和现实中的树正好上下颠倒了。接下来小 C 开始定义生长。某次生长操作用 T = grow(T’,d) 表示,T’表示生长前的树,T 表示生长之后的树。成长规律根据参数 d 决定。生长时,T’中所有深度为 d 的节点同时增加一个新的节点与之连接,得到的树即为 T。比如说下图中 (A) 为原树 T,(B) 为 grow(T,1),(C) 为grow(T,2)。

2021合肥市赛

小 C 又定义成长,表示一棵树经过一系列生长得到另一棵树的过程。令原树为 T0 ,总共 k 次生长操作,第 i 次生长的参数为 di ,则可以表示为:

T1 = grow(T0 ,d1 ) → T2 = grow(T1 ,d2 ) → ··· → Tk = grow(Tk−1 ,dk )

小 C 又定义种子为大小为 1、仅包含根节点的树。下图是一颗种子的成长过程。

2021合肥市赛


然而一个猜想需要诸多事实来支撑。小 C 又观察了许多棵树,然而树儿都长大了,小C 只能得到成长之后的树 T。他想知道对于一颗种子,存不存在某种成长过程,使得种子能长成树 T。于是小 C 把问题交给了你。

输入格式:

本题每个输入文件有多组测试数据。
第一行一个正整数 Q,表示数据组数。

对于每组数据,将会描述一棵成长之后的树 T;

每组数第一行两个正整数 n 和 r,表示树 T 的大小、T 的根,节点依次从 1 到 n 标号;

接下来 n − 1 行,每行两个整数 u 和 v,描述一条边 (u,v)。

保证 T 一定是一棵合法的树。

输出格式:

总共 Q 行,每行表示对应的树 T 是否存在成长过程,使得种子成长成 T,如果存在,输出 Yes,否则输出 No(请注意大小写)。

限制:

空间限制:512MByte
时间限制:2.5秒

样例:

输入:

【测试样例#1输入】

1

6 1

1 2

1 3

2 4

2 5

3 6

【测试样例#2输入】

1

6 1

1 2

2 3

3 4

1 5

5 6

【测试样例#3输入】

2

6 1

1 2

1 3

2 4

2 5

3 6

6 1

1 2

2 3

3 4

1 5

5 6

输出:

【测试样例#1输出】

Yes

【测试样例#2输出】

No

【测试样例#3输出】

Yes

No

提示:

【样例 1 解释】

这棵树的形态如下。

2021合肥市赛


此为题面描述的成长过程中的例子。

【样例 2 解释】

这棵树的形态如下。

2021合肥市赛


一颗种子不存在某种成长方式变成这棵树。

【数据范围】
对于 10% 的数据:n ≤ 5;
对于 30% 的数据:n ≤ 10;
对于 50% 的数据:n ≤ 100;
对于 70% 的数据:n ≤ 3 × 1e3;
对于所有数据:1 ≤ Q ≤ 10,1 ≤ n ≤ 1e5,1 ≤ r ≤ n。

代码

#include "iostream"
#include "vector"
#include "queue"
#include "cstring"
using namespace std;
const int N = 1e5+10;


struct node{
    vector<int> cls;
    int p;
    int n1,n2;//n1表示孩子结点数,n2表示孩子中的叶子结点数
}trees[N];


vector<int> deeps[N];//树结点深度
int nums[N];//标记深度为i的叶子结点数

priority_queue<int,vector<int>,greater<int> > ns;//小根堆,元素小的优先级高,注意这里的写法都是固定的

int dfs(int root,int d);



int main(){
    int q;
    scanf("%d",&q);
    while (q--){
        int n,r;
        scanf("%d%d",&n,&r);
        memset(trees,0, sizeof(trees));
        memset(deeps,0, sizeof(deeps));
        memset(nums,0, sizeof(nums));
        ns = priority_queue<int,vector<int>,greater<int> > ();

        int u,v;
        for (int i = 1; i <= n - 1 ; ++i) {//n-1条边
            scanf("%d%d",&u,&v);
            trees[u].cls.push_back(v);
            trees[v].p = u;
            trees[u].n1 ++ ;
        }

        dfs(r,1);

        if(nums[n]){//说明是单链
            printf("Yes\n");
            continue;
        }


//        for (int i = 1; i <= n ; ++i) {
//            for (int j = 0; j < deeps[i].size() ; ++j) {
//                cout<<deeps[i][j]<<" ";
//            }
//            cout<<endl;
//        }
//
//        for (int i = 1; i <= n ; ++i) {
//            cout<<nums[i]<<" ";
//        }
//
//        return 0;
//
//        while(!ns.empty()){
//            cout<<ns.top()<< " "<<nums[ns.top()]<<endl;ns.pop();
//        }
//        return 0;

        while(!ns.empty()){
            int d = ns.top();//叶子结点深度是d,需要从d-1层结点开始删除
            int size = deeps[d - 1].size();

            if(size > nums[d]){//如果父结点数比当前的子结点数多,肯定不满足条件,直接输出No
                printf("No\n");
                break;
            }

            vector<int> newleaf;

            int flag = 0;
            for (int i = 0; i < deeps[d - 1].size(); ++i) {
                int x = deeps[d - 1][i];
                if(!trees[x].n2){//某个结点没有叶子结点,不满足条件
                    flag = 1;
                    break;
                }else{
                    trees[x].n1 --;
                    trees[x].n2 --;

                    if(x != r && trees[x].n1 == 0){//变成了叶子结点了,先缓存起来,注意 根结点不用管了
                        newleaf.push_back(i);//记录下标,防止遍历复杂度
                    }
                }
            }

            if(flag){
                printf("No\n");
                break;
            }

            if(size == nums[d]){
                ns.pop();
            }

            nums[d] -= size;//剪去叶子结点

            //处理新产生的叶子结点
            for (int i = newleaf.size() - 1; i >= 0 ; i--) {
                nums[d-1] ++ ;
                if(nums[d-1] == 1){
                    ns.push(d-1);//产生了新深度的叶子
                }
                int t = newleaf[i];
                int q = deeps[d-1][t];

                trees[trees[q].p].n2 ++ ;
                //对应deeps 要 删除该结点
                deeps[d-1].erase(deeps[d-1].begin() + t);
//                for (int j = 0; j < deeps[d-1].size() ; ++j) {
//                    if(deeps[d-1][j] == t){//该元素已经变为叶子了,删除
//                        deeps[d-1].erase(deeps[d-1].begin() + j);
//                        break;
//                    }
//                }
            }
        }
        if(ns.empty()){
            printf("Yes\n");
        }
    }
    return 0;
}
int dfs(int root,int d){
    for (int i = 0; i < trees[root].cls.size() ; ++i) {
        dfs(trees[root].cls[i],d+1);
    }
    //叶子结点
    if(trees[root].cls.empty()){
        trees[trees[root].p].n2++;//父结点的叶子结点数++
        nums[d]++;//标记深度为d的叶子结点数
        if(nums[d] == 1){//首次放入优先队列中
            ns.push(d);//按叶子优先级
        }
    }else{//非叶子结点加入deeps中
        deeps[d].push_back(root);
    }
}

第四题不知道题目(doge)

上一篇:行为树(Behavior trees)


下一篇:kaggle信用卡欺诈看异常检测算法——无监督的方法包括: 基于统计的技术,如BACON *离群检测 多变量异常值检测 基于聚类的技术;监督方法: 神经网络 SVM 逻辑回归