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]vu。因为要取最大的点,那么当然要去子节点中能够取得的最大的数。
  • 假如该节点要取子节点的最小值,那么 d p [ u ] = ∑ d p [ v ] v 是 u 的 子 节 点 dp[u]=\\sumdp[v]\\quad v是u的子节点 dp[u]=dp[v]vu。思考一下,因为要去最小的点,也就是取下面子节点中能取到的数的最小值。假设左子树只能取第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 暑假集训 个人排位赛

2022.07.15 暑假集训 个人排位赛

2022.07.14 暑假集训 个人排位赛

2022.07.14 暑假集训 个人排位赛

2022.07.14 暑假集训 个人排位赛

2022.07.10 暑假集训 个人排位赛