西安邮电大学第五届ACM-ICPC校赛(同步赛)

52 篇文章 1 订阅
6 篇文章 0 订阅

http://www.yyycode.cn/index.php/2020/05/30/%e8%a5%bf%e5%ae%89%e9%82%ae%e7%94%b5%e5%a4%a7%e5%ad%a6%e7%ac%ac%e4%ba%94%e5%b1%8aacm-icpc%e6%a0%a1%e8%b5%9b%ef%bc%88%e5%90%8c%e6%ad%a5%e8%b5%9b%ef%bc%89/


https://ac.nowcoder.com/acm/contest/5678

A、拯救咕咕咕之史莱姆

链接:https://ac.nowcoder.com/acm/contest/5678/A
来源:牛客网

信鸽王国有一位美丽的公主,被可恶的巫师囚禁在了城堡里,你是一位倾慕公主的勇者,准备去解救她。你来到了城堡外,发现有一只丑陋的史莱姆阻挡了你的去路,向你索要进堡费,你囊中羞涩,并不想给钱,于是你给它撒了“洞洞索命粉末”!
洞洞索命粉末:被撒此粉末它的身上就会出现一个大洞,从中毒的第二天开始,大洞每天早上会分裂出一个小洞,小洞在出现后的第四天会长成大洞(并开始分裂),每个洞在每天下午会减少它 3 点 HP,HP 为 0 时它就会死去。史莱姆很聪明,如果他意识到自己第二天就会死去,他就会向你求饶,让开道路。
PS:你从小道消息得知公主就快要饿死了,所以你要赶在 5 天之内进入城堡,如果 5 天之后史莱姆还没有向你求饶,那你只能氪金了。

输入描述:

测试输入包含若干测试用例,每个测试用例占一行,包含一个整数 n(long long范围内),表示史莱姆的初始 HP 值,当 n 为 0 时输入结束。

输出描述:

对每个测试用例,如果 5 天之内(包括第 5 天)史莱姆向你求饶,那就输出“AOLIGEI!”,否则,输出“DAAAAAMN!”,没有双引号。

示例1

输入

复制 5 73 77 0

5
73
77
0

输出

复制 AOLIGEI! AOLIGEI! DAAAAAMN!

AOLIGEI!
AOLIGEI!
DAAAAAMN!

思路:类似生兔子的dp,不过方便点的无脑方法就是观察样例一个个试过去。在73-77中挑一个数。

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5;
typedef long long LL;
LL dp[maxn];
int main(void)
{
	LL n;
	while(cin>>n&&n!=0)
	{
		//LL sum=18;
		if(n<=75) cout<<"AOLIGEI!"<<endl;
		else cout<<"DAAAAAMN!"<<endl;
	}

return 0;
}

E-无敌阿姨

链接:https://ac.nowcoder.com/acm/contest/5678/E
来源:牛客网

X 学校最近计划安排宿管阿姨帮每个宿舍的人晒被子,为了提高效率雇佣了一个无敌阿姨,已知无敌阿姨晒被子的方式如下:
1、进入当前有被子的最低层拿尽可能多的被子,每拿走 1 床被子体力值减 1;
2、如果当前层的被子被拿完且此时的体力值大于 k ,消耗 k 点体力值进入到上层楼;
3、在当前层拿尽可能多的被子,每拿走 1 床被子体力值减 1 ,重复步骤 2;
4、如果体力耗尽或者此时的体力小于等于 k ,将被子拿出去放到晾衣架,体力恢复为初始体力值;
PS:阿姨在没有取得被子之前上楼不消耗体力。
先给出楼的层数 n ,阿姨的体力值 m ,阿姨抱着被子上楼的体力消耗值 k ,每层的被子数 aia_iai​ ,问阿姨需要几次能够把所有被子拿出去?

输入描述:

输入包含多组数据,第一行包含一个数字 T(1≤T≤10)T(1 \le T \le 10)T(1≤T≤10),表示测试数据组数。接下来是T组数据,
每组数据第一行为三个整数 n,m,k(1≤n,m,k≤100)n,m,k(1 \le n,m,k \le 100)n,m,k(1≤n,m,k≤100)分别表示楼的层数,阿姨的体力值以及抱着被子上楼的体力消耗值。
第二行 n 个整数 a1,a2,a3,...,an(1≤ai≤100)a_1,a_2,a_3,...,a_n(1 \le a_i \le 100)a1​,a2​,a3​,...,an​(1≤ai​≤100) 表示每层的被子数。

输出描述:

每组数据输出包含一个整数,表示阿姨把所有的被子都拿出去需要的次数。

示例1

输入

复制 1 4 5 1 1 1 2 4

1
4 5 1
1 1 2 4

输出

复制 3

3

说明

第一次阿姨先从第一层拿一床被子,再上到第二层拿1床被子,再上到第三层拿一床被子,其中拿被子消耗体力为3,上楼消耗体力为2;第二次阿姨先从第三层拿一床被子,再上到第四层拿三床被子,其中拿被子消耗体力为4,上楼消耗体力为1;第三次阿姨直接从第四层拿一床被子消耗体力为1,全部为拿被子消耗的体力。

思路:模拟的思路一直比较弱,需要借助一些方法来模拟,比如双指针,这里我借助了双端队列模拟。在某场cfdiv4中我看到一个鸽鸽二道或者三道都是deque模拟的。deque用来做模拟题应该会比较方便

#include<iostream>
#include<vector>
#include<queue>
#include<deque>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5;
typedef long long LL;
 
int main(void)
{
    LL t;cin>>t;
    while(t--)
    {
        LL n,m,k;cin>>n>>m>>k;
        LL res=0;deque<LL> a;
 
        for(LL i=0;i<n;i++) { LL x;cin>>x;a.push_back(x);}
        LL p=m;
        LL floor=0;
        while(a.size()>0&&a.size()<=n)
        {
    //      cout<<"a.size()="<<a.size()<<endl;
                    LL t=a[0];
                    a[0]=a[0]-p;
                    p-=t;
                    if(a[0]<=0) a.pop_front(),floor++;
                    if(p<k||floor==n) res++,p=m;
                    else if(p>=k) p-=k;
                     
        //          cout<<"res="<<res<<endl;
        }
        cout<<res<<endl;
    }
 
return 0;
}

G-校车

链接:https://ac.nowcoder.com/acm/contest/5678/G
来源:牛客网

西安邮电大学有一辆从老校区到新校区的校车,总共有 n 个学生乘坐校车,在 aia_{i}ai​ 站上车,在 bib_{i}bi​ 站下车。学校打算去除一部分不必要的站点,请问需要保留多少站点,需要安排多少个座位?

输入描述:

输入 T 组数据 (1≤T≤10)(1 \le T \le 10)(1≤T≤10)
输入 n(1≤n≤105)n(1 \le n \le 10^{5})n(1≤n≤105)
输入 n 组 ai,bi(1≤ai,bi≤109)a_{i},b_{i}(1 \le a_{i},b_{i} \le 10^{9})ai​,bi​(1≤ai​,bi​≤109)

输出描述:

输出保留站点数,座位数。

示例1

输入

复制 1 3 1 2 1 3 2 4

1
3
1 2
1 3
2 4

输出

复制 4 2

4 2

思路:对一段数轴进行差分,需要的座位是累加差分的最大值,统计有多少个不重站点就是答案。学生的人数比站点的范围少很多,要离散化。

离散化板子:为了方便debug以后把离散化的板子里面的二分改成STL的

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int maxn = 3e5+10;
LL n, m;
LL a[maxn], b[maxn],c[maxn];
 
vector<LL> v;
LL find(LL x)
{
    return lower_bound(v.begin(),v.end(),x)-v.begin();
}
int main(void)
{
    LL t;cin>>t;
    while(t--)
    {
        v.clear();//多组清空
        LL n;cin>>n;
        for(LL i=1;i<=n+10;i++) a[i]=b[i]=0;
        for(LL i=0;i<n;i++)
        {
            cin>>a[i]>>b[i];
            v.push_back(a[i]);v.push_back(b[i]);
        }
        sort(v.begin(),v.end());
        v.erase(unique(v.begin(),v.end()),v.end());
        for(LL i=0;i<v.size();i++) c[i]=0;
        for(LL i=0;i<n;i++)
        {
            c[find(a[i])]++;
            c[find(b[i])]--;
        }
        LL cnt=c[0], res=cnt;
        for(LL i=1;i<v.size();i++)
        {
            cnt+=c[i];
            res=max(res,cnt);
        }
        cout<<v.size()<<' '<<res<<endl;
    }
 
return 0;
}

H-中位因数

链接:https://ac.nowcoder.com/acm/contest/5678/H
来源:牛客网

 

题目描述

给出函数的定义如下:
f(x)是所有能够整除 x 的数(包含 1 和 x )中的中位数向下取整的大小,
g(x)=∑i=1xf(i)g(x)=\sum_{i = 1}^{x}{f(i)}g(x)=∑i=1x​f(i)

输入描述:

输入包含多组数据,第一行为一个数字 T(1≤T≤10)T(1 \le T \le 10)T(1≤T≤10) ,表示测试数据组数。
接下来是 T 组数据,每组数据为一行,包含一个整数 x(1≤x≤1000000)x(1 \le x \le1000000)x(1≤x≤1000000)

输出描述:

每组数据输出包含一个整数,表示 g(x) 的值,结果要求对 1e9+7 取模。

示例1

输入

复制 3 1 2 3

3
1
2
3

输出

复制 1 2 4

1
2
4

说明

能够整除 1 的数字有 1 ,故 f(1)=1;
能够整除 2 的数字有 1,2 所以中位数为⌊1+22⌋=1\lfloor \frac{1+2}{2} \rfloor = 1⌊21+2​⌋=1,故 f(2) = 1;
能够整除 3 的数字有 1,3 ,所以中位数为1+32=2\frac{1+3}{2}=221+3​=2 ,故 f(3) = 2;
从而得出 g(1) = 1,g(2) = 2,g(3) = 4 。

示例2

输入

复制 1 1000000

1
1000000

输出

复制 677045223

677045223

思路:对一个数n来说,他的因子会在根号n两侧,那么根号n左边有多少个,根号n右边就有多少个。那么题目的中位因数的意思是让我们找最靠近根号n的两个。(当然可能==根号n的情况)

那么我们进行枚举,假设一个数为x,它会有很多因子,比如有一组配对因子是i,j(我们假设i<=j).

那么先令a[x]=(i+j)/2,使(i+j)/2是x的中位因数,之后不断更新,更新到最后a[x]里面存的是i和j最接近的一对因数的中位因数。

当时没搞懂这个循环,记录一下:类似桶,a[i*j==x],x的因数有i,j,且默认i<=j,然后枚举更新x的中位因数

比如16,刚开始a[16==1*16]=8;到后面会更新到a[16==4*4]==4;

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5,mod=1e9+7,M=1e6;
int ans[N],a[N],n,t;
int main(){
    memset(a,0x7f,sizeof(a));
	for(int i=1;i<=1000;i++)
		for(int j=i;i*j<=M;j++)
		{
			 {
			     a[i*j]=min(a[i*j],(i+j)/2);//类似桶,a[i*j==x],x的因数有i,j,且默认i<=j,然后枚举更新x的中位因数
			 }
		} 
	for(int i=1;i<=M;i++) ans[i]=(ans[i-1]+a[i])%mod;
	cin>>t;
	while(t--){
		cin>>n;
		cout<<ans[n]<<endl;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值