2022牛客寒假算法基础集训营1全部题解
Posted quinn18
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2022牛客寒假算法基础集训营1全部题解相关的知识,希望对你有一定的参考价值。
文章目录
- A 九小时九个人九扇门 dp
- H 牛牛看云 思维
- F 中位数切分 思维
- I B站与各唱各的 数学
- D 牛牛做数论 数学
- B 炸鸡块君与FIFA22 倍增/分块/线段树【补】
- K 冒险公社 dp【补】
- G ACM is all you need 【待补】
- 总结
比赛链接
A 九小时九个人九扇门 dp
题目链接
题意:
一个数字的数字根是指:将该数字各数位上的数字相加得到一个新的数,直到得到的数字小于
10
10
10 为止.。设置小于
10
10
10 的数字,其数字根就为其本身。
k
k
k 个人能够打开门上数字为d的一扇数字门,当且仅当这
k
k
k 个人的腕表数字之和的数字根恰好为
d
d
d。
(
1
<
=
n
<
=
1
e
5
,
1
<
a
i
<
=
1
e
9
)
(1<=n<=1e5,1<ai<=1e9)
(1<=n<=1e5,1<ai<=1e9)
题解:
状态
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 表示考虑了前
i
i
i 个数,选择了一些数字使得数字根为
j
j
j 的方案数
转移方程
不加当前位使得数字根为
j
j
j 的方案数为上一位继承来
d
p
[
i
]
[
j
]
+
=
d
p
[
i
−
1
]
[
j
]
;
dp[i][j] += dp[i - 1][j];
dp[i][j]+=dp[i−1][j];
加上当前位使得数字根为
f
(
a
[
i
]
∗
10
+
j
)
f(a[i]*10+j)
f(a[i]∗10+j) 的方案数为上一位继承来
d
p
[
i
]
[
f
(
a
[
i
]
∗
10
+
j
)
]
+
=
d
p
[
i
−
1
]
[
j
]
;
dp[i][f(a[i]*10+j)] += dp[i - 1][j];
dp[i][f(a[i]∗10+j)]+=dp[i−1][j];
当前位的方案数+1
d
p
[
i
]
[
f
(
a
[
i
]
)
]
+
+
;
dp[i][f(a[i])]++;
dp[i][f(a[i])]++;
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+100;
const int M=998244353;
int t;
int a[N];
int b[N];
int f[10][N];
int fun(int n)
if(n<10) return n;
while(n>=10)
int m=0;
while(n)
m+=n%10;
n/=10;
n=m;
return n;
signed main()
t=1;
while(t--)
int n;
cin>>n;
for(int i=1; i<=n; i++)
cin>>a[i];
a[i]=fun(a[i]);
for(int j=0; j<=9; j++)
int tmp=fun(a[i]*10+j);
f[j][i]+=f[j][i-1]%M;
f[tmp][i]=(f[tmp][i]+f[j][i-1])%M;
f[a[i]][i]++;
for(int i=1; i<=9; i++)
cout<<f[i][n]%M<<" ";
cout<<endl;
return 0;
H 牛牛看云 思维
题目链接
题意:
求
n
n
n
n
n
n
Σ
Σ
Σ
Σ
Σ
Σ
∣
a
i
+
a
j
−
1000
∣
∣ai+a j −1000∣
∣ai+aj−1000∣
i
i
i=1
j
j
j=
i
i
i
(
0
<
a
i
<
=
1000
,
n
<
=
1000000
)
(0<ai<=1000, n<=1000000)
(0<ai<=1000,n<=1000000)
题解:
因为这个
n
n
n 很打,
a
i
ai
ai很小
就从
a
i
ai
ai 入手
记录
a
i
ai
ai 的个数枚举
a
i
ai
ai
直接计算答案
假如
a
i
=
=
a
j
ai==aj
ai==aj ans=自己和自己+自己和别人
/
2
/2
/2 (因为
j
j
j 是从
i
i
i 开始的 所以
/
2
/2
/2
a
i
!
=
a
j
ai!=aj
ai!=aj ans=
c
n
t
[
a
i
]
∗
c
n
t
[
a
j
]
/
2
cnt[ai]*cnt[aj]/2
cnt[ai]∗cnt[aj]/2
vector<int> g[N];
signed main()
ios_base::sync_with_stdio(0), cin.tie(0); cout.tie(0);
int n;cin>>n;
for(int i=1; i<=n; i++)
int x;
cin>>x;
g[x].push_back(i);
int ans=0;
int a, b;
for(int i=0; i<=1000; i++)
for(int j=i; j<=1000; j++)
int a=g[i].size();
int b=g[j].size();
if(i==j)
ans+=(a+a*(a-1)/2)*abs(i+i-1000);
else
ans+=a*b*abs(i+j-1000);
cout<<ans<<endl;
return 0;
F 中位数切分 思维
题目链接
题意:
给定一个长为
n
n
n 的数组
a
a
a 和一个整数
m
m
m,求最多可以划分成多少段,使得每一段的中位数都大于等于
m
m
m。
(
1
<
a
i
,
m
<
=
1
e
9
,
1
<
=
n
<
=
1
e
5
)
(1<ai, m<=1e9, 1<=n<=1e5)
(1<ai,m<=1e9,1<=n<=1e5)
题解:
原数组大于等于m的记为1,记录
c
n
t
1
cnt1
cnt1 个
小于的记为-1,记录
c
n
t
2
cnt2
cnt2 个
当一段的
s
u
m
>
=
1
sum>=1
sum>=1 的时候这一段中位数就
>
=
m
>=m
>=m
然后就去拿
1
1
1 的去中和
−
1
-1
−1, 最大的段数就是先把负数中和了使得
s
u
m
=
=
0
sum==0
sum==0 再加上一个
1
1
1,假如
c
n
t
1
−
c
n
t
2
<
=
0
cnt1-cnt2<=0
cnt1−cnt2<=0则不存在,不然段数为
c
n
t
1
−
c
n
t
2
cnt1-cnt2
cnt1−cnt2个 。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
const double eps=1e-4;
int n, m;int a[N];
signed main()
ios_base::sync_with_stdio(0), cin.tie(0); cout.tie(0);
int t;
cin>>t;
while(t--)
cin>>n>>m;
int p=0;
for(int i=1; i<=n; i++)
cin>>a[i];
if(a[i]>=m) p++;
if(p-(n-p)>0) cout<<p-(n-p)<<endl;
else cout<<-1<<endl;
return 0;
I B站与各唱各的 数学
题目链接
题意:
分子为欧拉函数
题解: 以上是关于2022牛客寒假算法基础集训营1全部题解的主要内容,如果未能解决你的问题,请参考以下文章
打表呜呜呜
最小值是
下一个数是210
就发现是素数的乘积
2
,
2
∗
3
,
2
∗
3
∗
5
2,2*3,2*3*5
2,2∗3,