ABC163(Atcoder beginner contest 163)部分题解

题解

A

思路: 水题,π保留7位小数乘法就可以啦。

话说不会有人不知道π≈3.1415926吧

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;

double n,p=3.14159265358979;

signed main()
{
	cin>>n;
	cout<<fixed<<setprecision(15)<<2*n*p<<endl;
	
	return 0;
}

B

思路: 直接模拟即可。

如果总天数小于等于假期的天数,就输出两者的差;否则输出-1。

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;

int d,n,tmp;

signed main()
{
	cin>>d>>n;
	for (int i=1;i<=n;i++)
	{
		cin>>tmp;
		d-=tmp;
	}
	if (d>=0)  cout<<d<<endl;
	else cout<<-1<<endl;
}

C

思路: 统计每人作为上司的次数即可。

前三题有多水后两题就有多难

思路:

#include <bits/stdc++.h>
#define int long long
using namespace std;

int n,tmp;
int visited[200005];

signed main()
{
	cin>>n;
	for (int i=2;i<=n;i++)
	{
		cin>>tmp;
		visited[tmp]++;
	}
	for (int i=1;i<=n;i++)  cout<<visited[i]<<endl;
	cout<<endl;
	
	return 0;
}

D

思路:

看数据范围: N ≤ 2 × 1 0 5 N≤2×10^5 N2×105 1 ≤ K ≤ N + 1 1≤K≤N+1 1KN+1

很明显,高桥君想让我们搞出一个O(n)的算法而不是O(1)的算法。

所以,我们枚举选的数的数量i,每次尝试在O(1)时间内算出取 i i i个数的不同和的数量。

为了方便,我们需要去掉前面的那个 1 0 100 10^{100} 10100;同时为了防止影响答案的正确性,我们设定x个数的和与y个数的和一定不同(x≠y),这样每次算 取 i i i个数的不同和的数量 就独立了。

好的,一切都处理完了,我们开始思考怎么O(1)时间算它。

即,所有能够取到的和一定是连续的(很明显啊,读者自行思考 ),而一个连续的闭区间 [ l , r ] [l,r] [l,r]的数的数量为 r − l + 1 r-l+1 rl+1,所以我们只需要求出 l l l r r r的值。易得:

r = Σ j = n − i + 1 n j r=Σ_{j=n-i+1}^n j r=Σj=ni+1nj
l = Σ j = 0 i − 1 j l=Σ_{j=0}^{i-1} j l=Σj=0i1j

注意这里的等差数列求和可以用公式,即 Σ l r i = ( l + r ) × ( r − l + 1 ) / 2 Σ_l^r i=(l+r)×(r-l+1)/2 Σlri=(l+r)×(rl+1)/2

综上所述,答案就是: Σ i = k n + 1 r − l + 1 Σ_{i=k}^{n+1} r-l+1 Σi=kn+1rl+1

时间复杂度 O ( n − k ) O(n-k) O(nk)

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;

int n,k,ans=0;

int get_sum(int l,int r)
{
	return (((l+r)*(r-l+1))/2ll)%mod;
}

signed main()
{
	cin>>n>>k;
	for (int i=k;i<=n+1;i++)  ans=(ans+((get_sum(n-i+1,n)-get_sum(0,i-1)+1)%mod+mod)%mod)%mod;
	cout<<ans%mod<<endl;
	
	return 0;
}

花絮

本题在我们班的花絮极多:

①我: 切掉
②大佬A: 压到两行再提交!
③大佬B: 哇哇哇,这么难? (10秒后)哦哦哦,这么简单!
④大佬C: 一边做题一边唱歌,连续多次WA后自闭。

代码

E


前言

考试的时候构造了一个矩阵,其中第 i i i列的第 j j j行表示第 i i i个小屁孩到第 j j j个位置的幸福度。

那么,我们就需要取 n n n个数,其中每行仅取一个数且每列也仅取一个数,然后答案就是这些数的综合的最大值

于是开始想dp,在两次WA,一次RE,一次MLE以及两次TLE中自闭……


思路(正解)

赛后诸葛亮

考虑贪心。

我们应该发现,我们应该让积极性更高的小屁孩先选择位置。那么,他/她 一定会站在目前唯一的未站小屁孩的区间的左端点或右端点。由于每次小屁孩都站在端点处,所以未被选择的区间有且仅有一个

于是这就成为了一个不能再明显的区间动规。状态设计 d p l , r dp_{l,r} dpl,r,表示目前唯一未站小屁孩的区间为 [ l , r ] [l,r] [l,r] d p l , r dp_{l,r} dpl,r存下了目前得到了最大幸福值

然后推一下状态转移。注意这里要分类讨论:

编号为 i i i的小屁孩跑到左端点去了! 他导致现在的区间成为了 [ l + 1 , r ] [l+1,r] [l+1,r],且他贡献了 a i × ∣ i − l ∣ a_i×|i-l| ai×il的幸福值;
编号为 i i i的小屁孩跑到右端点去了! 他导致现在的区间成为了 [ l , r − 1 ] [l,r-1] [l,r1],且他贡献了 a i × ∣ i − r ∣ a_i×|i-r| ai×ir的幸福值。

后记

思路出来后,我开始打 d p dp dp,结果死得一批得惨,连调都调不出来(还不是我太弱)。

于是,本蒟蒻臭不要脸地看了另外一篇题解,启发我打了记忆化搜索以防止调试时间过长(因为动规 d p dp dp需要逆推,而记忆化搜索是顺推;注意动规 d p dp dp总能装换为记搜)。

然后? 没有然后了。你们看不到跌宕起伏的剧情了

顺便提一句,大家觉得我LaTeX修炼得怎么样(E题)?

代码
//发现D题没放代码,赶紧补一下

#include <bits/stdc++.h>
#define int long long
using namespace std;

int n,dp[2005][2005];

struct node
{
	int rt;
	int num;
}a[5005];

bool cmp(node a,node b)
{
	return a.num>b.num;
}

int work(int now,int l,int r)
{
	if (l>r)  return a[now].num;
	if (dp[l][r]!=-1)  return dp[l][r];
	
	int first=work(now+1,l+1,r)+a[now].num*abs(a[now].rt-l);
	int second=work(now+1,l,r-1)+a[now].num*abs(a[now].rt-r);
	dp[l][r]=max(dp[l][r],max(first,second));
	
	return dp[l][r];
}

signed main()
{
	cin>>n;
	memset(dp,-1,sizeof(dp));
	for (int i=1;i<=n;i++)  cin>>a[i].num,a[i].rt=i;
	
	sort(a+1,a+n+1,cmp);
	cout<<work(1,1,n)<<endl;
	
	return 0;
}

总结

①排名: 621(中国59)

本次比赛排名较高,总结经验
(1)一些大佬看到Unrated后溜了;
(2)第五题特别难,于是前四题就拼手速;我花了19分钟创纪录切掉 了前四题,但是由于太弱在第五题自闭;
(3)题目偏向于本蒟蒻擅长的数学
(4)赛前进答疑对AT发了一句话:
“I hope I can get a good mark this time!”
(5)认真地上了学校的文化课。

②总分: 1000(赛后1500)
哇哇哇,还是没进步,我真的弱到极致了呀 o ( ╥ ﹏ ╥ ) o q w q o(╥﹏╥)o qwq o()oqwq

AtCoder Beginner Contest 134 是一场 AtCoder 的入门级比赛,以下是每道题的简要题解: A - Dodecagon 题目描述:已知一个正十二边形的边长,求它的面积。 解题思路:正十二边形的内角为 $150^\circ$,因此可以将正十二边形拆分为 12 个等腰三角形,通过三角形面积公式计算面积即可。 B - Golden Apple 题目描述:有 $N$ 个苹果和 $D$ 个盘子,每个盘子最多可以装下 $2D+1$ 个苹果,求最少需要多少个盘子才能装下所有的苹果。 解题思路:每个盘子最多可以装下 $2D+1$ 个苹果,因此可以将苹果平均分配到每个盘子中,可以得到最少需要 $\lceil \frac{N}{2D+1} \rceil$ 个盘子。 C - Exception Handling 题目描述:给定一个长度为 $N$ 的整数序列 $a$,求除了第 $i$ 个数以外的最大值。 解题思路:可以使用两个变量 $m_1$ 和 $m_2$ 分别记录最大值和次大值。遍历整个序列,当当前数不是第 $i$ 个数时,更新最大值和次大值。因此,最后的结果应该是 $m_1$ 或 $m_2$ 中较小的一个。 D - Preparing Boxes 题目描述:有 $N$ 个盒子和 $M$ 个物品,第 $i$ 个盒子可以放入 $a_i$ 个物品,每个物品只能放在一个盒子中。现在需要将所有的物品放入盒子中,每次操作可以将一个盒子内的物品全部取出并分配到其他盒子中,求最少需要多少次操作才能完成任务。 解题思路:首先可以计算出所有盒子中物品的总数 $S$,然后判断是否存在一个盒子的物品数量大于 $\lceil \frac{S}{2} \rceil$,如果存在,则无法完成任务。否则,可以用贪心的思想,每次从物品数量最多的盒子中取出一个物品,放入物品数量最少的盒子中。因为每次操作都会使得物品数量最多的盒子的物品数量减少,而物品数量最少的盒子的物品数量不变或增加,因此这种贪心策略可以保证最少需要的操作次数最小。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值