2022.07.13 暑假集训 个人排位赛
Posted 晁棠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2022.07.13 暑假集训 个人排位赛相关的知识,希望对你有一定的参考价值。
2022.07.13 暑假集训 个人排位赛(八)
赛后反省
中规中矩,感觉现在还是开始慢慢刷一刷动态规划了。两道动态规划没有做出。
Problem A
出处
Codeforces-1153D
题解
树形DP。
每一个父节点都是根据子节点的情况去获得的,相当于一个从叶子结点开始向上传递的过程。设dp[i]代表的是以i为根的子树中,i只能够取叶子结点中的第dp[i]大的点。
那么,当i是叶子结点的时候,显然dp[i]=1;
在其他结点的时候,分两种情况。
- 假如该节点要取子节点的最大值,那么 d p [ u ] = m i n d p [ v ] v 是 u 的 子 节 点 dp[u]=min\\dp[v]\\\\quad v是u的子节点 dp[u]=mindp[v]v是u的子节点。因为要取最大的点,那么当然要去子节点中能够取得的最大的数。
- 假如该节点要取子节点的最小值,那么 d p [ u ] = ∑ d p [ v ] v 是 u 的 子 节 点 dp[u]=\\sumdp[v]\\quad v是u的子节点 dp[u]=∑dp[v]v是u的子节点。思考一下,因为要去最小的点,也就是取下面子节点中能取到的数的最小值。假设左子树只能取第2大的数,右子树只能取第4大的数,那么假设两棵树合并之后,父节点只能够去两者的最小值,那么也就是第6大的数了。
代码
// Good Good Study, Day Day AC.
#include <iostream>
#include <stdio.h>
#include <cstdio>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <cstring>
#include <math.h>
#include <cmath>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <map>
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#define ffor(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define rrep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define mst(v,s) memset(v,s,sizeof(v))
#define IOS ios::sync_with_stdio(false),cin.tie(0)
#define ll long long
#define INF 0x7f7f7f7f7f7f7f7f
#define inf 0x7f7f7f7f
#define PII pair<int,int>
#define int long long
using namespace std;
const int N = 3e5 + 5;
int n, T = 1;
int a[N];
vector<int> ve[N];
int dp[N], k;
void dfs(int u)
if (!ve[u].size())
dp[u] = 1;
k++;
return;
int minn = INF;
for (auto v : ve[u])
dfs(v);
minn = min(dp[v], minn);
dp[u] += dp[v];
if (a[u]) dp[u] = minn;
return;
void ready()
cin >> n;
ffor(i, 1, n) cin >> a[i];
ffor(i, 2, n)
int v = i, u;
cin >> u;
ve[u].push_back(v);
dfs(1);
int ans = k - dp[1] + 1;
cout << ans;
return;
void work()
signed main()
IOS;
// cin>>T;
while (T--)
ready();
work();
return 0;
Problem B
出处
Codeforces-452B
题解
选三个点,使得线段距离最短。
那么根据样例2,一条直线的提示,我们也可以对斜对角先进行类似的操作。
然后整合一下,对于矩形来说,只在以下两种情况中选择一种就是最大值。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QnPQbY8o-1657725805385)(C:\\Users\\k’y\\AppData\\Roaming\\Typora\\typora-user-images\\image-20220713230113490.png)]
代码
// Good Good Study, Day Day AC.
#include <iostream>
#include <stdio.h>
#include <cstdio>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <cstring>
#include <math.h>
#include <cmath>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <map>
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#define ffor(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define rrep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define mst(v,s) memset(v,s,sizeof(v))
#define IOS ios::sync_with_stdio(false),cin.tie(0)
#define ll long long
#define INF 0x7f7f7f7f7f7f7f7f
#define inf 0x7f7f7f7f
#define PII pair<int,int>
#define int long long
using namespace std;
int T=1;
double n,m;
void ready()
cin>>n>>m;
if(n==0)
cout<<n<<' '<<1<<'\\n';
cout<<n<<' '<<m<<'\\n';
cout<<n<<' '<<0<<'\\n';
cout<<n<<' '<<m-1<<'\\n';
return;
if(m==0)
cout<<1<<' '<<m<<'\\n';
cout<<n<<' '<<m<<'\\n';
cout<<0<<' '<<m<<'\\n';
cout<<n-1<<' '<<m<<'\\n';
return;
/*
if(n<=2)
cout<<0<<' '<<0<<'\\n';
cout<<n<<' '<<m<<'\\n';
cout<<n<<' '<<0<<'\\n';
cout<<0<<' '<<m<<'\\n';
return;
if(m<=2)
cout<<0<<' '<<0<<'\\n';
cout<<n<<' '<<m<<'\\n';
cout<<0<<' '<<m<<'\\n';
cout<<n<<' '<<0<<'\\n';
return;
*/
if(n>=m)
double ans1=2*sqrt(n*n+(m-1)*(m-1))+sqrt(n*n+m*m);
double ans2=2*sqrt(n*n+m*m)+n;
if(ans1>=ans2)
cout<<0<<' '<<1<<'\\n';
cout<<n<<' '<<m<<'\\n';
cout<<0<<' '<<0<<'\\n';
cout<<n<<' '<<m-1<<'\\n';
else
cout<<0<<' '<<0<<'\\n';
cout<<n<<' '<<m<<'\\n';
cout<<0<<' '<<m<<'\\n';
cout<<n<<' '<<0<<'\\n';
return ;
else
double ans1=2*sqrt(m*m+(n-1)*(n-1))+sqrt(n*n+m*m);
double ans2=2*sqrt(n*n+m*m)+m;
if(ans1>=ans2)
cout<<1<<' '<<0<<'\\n';
cout<<n<<' '<<m<<'\\n';
cout<<0<<' '<<0<<'\\n';
cout<<n-1<<' '<<m<<'\\n';
else
cout<<0<<' '<<0<<'\\n';
cout<<n<<' '<<m<<'\\n';
cout<<n<<' '<<0<<'\\n';
cout<<0<<' '<<m<<'\\n';
void work()
signed main()
IOS;
ready();
//cin>>T;
while (T--)
work();
return 0;
Problem C
出处
Codeforces-229D
题解
DP
dp[i]为当以i结尾时达到满足条件的状态需要多少步操作。las[i]为当以i为结尾并且能满足条件时该序列最后一个数是多少。
枚举i之前的j,如果区间[j+1,i]之间的和大于las[j],则说明这是一种满足条件的变换,区间[j+1,i]合并的次数为i-j-1。那么在这个情况下所需要的操作次数即为dp[j]+i-j-1。如果dp[i]>=dp[j]+i-j-1,即可更新。
代码
// Good Good Study, Day Day AC.
#include <iostream>
#include <stdio.h>
#include <cstdio>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <cstring>
#include <math.h>
#include <cmath>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <map>
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#define ffor(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define rrep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define mst(v,s) memset(v,s,sizeof(v))
#define IOS ios::sync_with_stdio(false),cin.tie(0)
#define ll long long
#define INF 0x7f7f7f7f7f7f7f7f
#define inf 0x7f7f7f7f
#define PII pair<int,int>
#define int long long
using namespace std;
const int N = 5005;
int n, T = 1;
int sum[N], a[N];
int las[N], dp[N];
void ready()
cin >> n;
ffor(i, 1, n)
cin >> a[i];
sum[i] = sum[i - 1] + a[i];
dp[i] = las[i] = INF;
dp[1] = 0; las[1] = a[1];
void out()
cout << " dp \\n";
ffor(i, 1, n) cout << dp[i] << ' ';
cout << " \\n las \\n";
ffor(i, 1, n) cout << las[i] << ' ';
cout << '\\n';
cout << '\\n';
void work()
ffor(i, 2, n)
ffor(j, 0, i - 1)
if (las[j] <= sum[i] - sum[j] && dp[i] >= dp[j] + i - j - 1)
las[i] = sum[i] - sum[j];
dp[i] = dp[j] + i - j - 1;
//out();
//cout << " i = " << i << " dp = " << dp[i] << " las = " << las[i] << '\\n';
cout << dp[n];
signed main()
IOS;
// cin>>T;
while (T--)
ready();
work();
return 0;
Problem D
出处
Codeforces-229A
题解
算出每一个位置,离它最近的1在哪里,然后每一列地求和,输出最小即可。
需要注意,如果向右转的话排在最后一个的会去到最前面去。
代码
// Good Good Study, Day Day AC.
2022.07.13 暑假集训 个人排位赛