题解
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 N≤2×105, 1 ≤ K ≤ N + 1 1≤K≤N+1 1≤K≤N+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
r−l+1,所以我们只需要求出
l
l
l与
r
r
r的值。易得:
r
=
Σ
j
=
n
−
i
+
1
n
j
r=Σ_{j=n-i+1}^n j
r=Σj=n−i+1nj
l
=
Σ
j
=
0
i
−
1
j
l=Σ_{j=0}^{i-1} j
l=Σj=0i−1j。
注意这里的等差数列求和可以用公式,即 Σ l r i = ( l + r ) × ( r − l + 1 ) / 2 Σ_l^r i=(l+r)×(r-l+1)/2 Σlri=(l+r)×(r−l+1)/2
综上所述,答案就是: Σ i = k n + 1 r − l + 1 Σ_{i=k}^{n+1} r-l+1 Σi=kn+1r−l+1。
时间复杂度 O ( n − k ) O(n-k) O(n−k)。
#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×∣i−l∣的幸福值;
②原编号为
i
i
i的小屁孩跑到右端点去了! 他导致现在的区间成为了
[
l
,
r
−
1
]
[l,r-1]
[l,r−1],且他贡献了
a
i
×
∣
i
−
r
∣
a_i×|i-r|
ai×∣i−r∣的幸福值。
后记
思路出来后,我开始打 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