codeforce Round 734 div3 problem solving Report

Posted by witham on Thu, 13 Jan 2022 23:05:31 +0100

summary

In fact, there is nothing to summarize about this game. I didn't play this game on my birthday that day. I found time to participate in the virtual game the next day. The problem is not difficult. It is a thinking problem with a small amount of code. I still encountered a lot of stuck problems when doing it. After that, I found that many of my writing methods were not good enough. Write a problem solution here and record this set of problems. If there is something wrong, please send me a private letter to discuss it.

A. Polycarp and Coins

This A is the basic check-in. Judge n%3 the result to determine whether it is the same or more than 1 yuan or more than 2 yuan. There are no pits

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int t,n,ans;
	cin>>t;
	while(t--)
	{
		int a=100;
		cin>>n;
		if(n%3==0)cout<<n/3<<" "<<n/3<<endl;
		if(n%3==1)cout<<n/3+1<<" "<<n/3<<endl;
		if(n%3==2)cout<<n/3<<" "<<n/3+1<<endl;	
	}
	return 0;
 } 

B1,2 Wonderful Coloring -

Both questions B are similar. If you know B2, you don't have to talk about B1. Here's how B2 works. The title gives an array and some colors. We are required to dye to ensure that the four requirements given by the title are met. Then we only need to record the number of occurrences of each number. If it exceeds k times, it shall be counted as k times. All the rest together. Finally, take an integer to get the number of cells that can be dyed. The statistics of specific dyeing schemes only need to fill in each number in order. Use modk to maintain the current color. Can meet the requirements of the topic. This construction problem only needs to meet the requirements. It doesn't need to be the same as its answer. So we just need to ensure that the conditions are met.

#include<bits/stdc++.h>
using namespace std;
vector<int> cnt[200010];
int ans[200010];
int main()
{
	int t,n,k ;
	cin>>t;
	while(t--)
	{
		cin>>n>>k;
		for(int i=1,a;i<=n;i++)
		{
			scanf("%d",&a);
			cnt[a].push_back(i);
		}
		int u=0;
		for(int i=1;i<=n;i++)
		{
			u+=min(k,(int)cnt[i].size());
			ans[i]=0;
		}
		u=u/k*k;
		int color=1;
		for(int i=1;i<=n;i++)
		{
			if(u==0)break;
			for(int j=0;j<min(k,(int)cnt[i].size());j++)
			{
				if(u==0)break;
				ans[cnt[i][j]]=color;//The location of the j-th occurrence of the number i stored in the cnt. 
				color=color%k+1;
				u--;
			}
		}
		for(int i=1;i<=n;i++)
		cout<<ans[i]<<" ";
		cout<<endl; 
		for(int i=1;i<=n;i++)
			cnt[i].clear();  
	}
	return 0;
 } 

C. Interesting Story

There is no good idea about this problem just now. But after observation, we found that we can change the problem. Because there are only five letters. We can enumerate each letter as the most letters. Then take max for the results of the five cases. The specific process can be achieved by designing an eigenvalue function. Represents the difference between the number of characters in the current string that is not equal to a letter minus the number of characters in the letter. Then take a sequence. Keep increasing. The first one greater than 0 indicates that the condition is not met. Complexity requires only one sort. nlogn can solve the problem

#include<bits/stdc++.h>
using namespace std;
string s[200010];
int a[200010];
int get(string ss,char q)
{
	int ans=0;
	int len=ss.size();
	for(int i=0;i<len;i++)
	if(ss[i]!=q)ans++;
	else ans--;
	return ans;
}
int main()
{
	int t,n;
	cin>>t;
	while(t--)
	{
		char oo[6];
		oo[1]='a';oo[2]='b';oo[3]='c';oo[4]='d';oo[5]='e';
		cin>>n;
		int ans=0;
		for(int i=1;i<=n;i++)
		cin>>s[i];
		for(int i=1;i<=5;i++)
		{
			for(int j=1;j<=n;j++)
			{
				a[j]=get(s[j],oo[i]);
			}
			sort(a+1,a+n+1);
			int tmp=0;
			for(int j=1;j<=n;j++)
			{
				tmp+=a[j];
				if(tmp>=0){
					ans=max(ans,j-1);
					break;
				}
			}
			if(tmp<0)ans=n;
		}
		cout<<ans<<endl;
	}
	return 0;
 } 

D1.Domino (easy version)

A classic domino problem. Give n, m and the number of dominoes required to be placed horizontally. We can easily find it first. If n and m are both odd. It can't be full. So rows and columns have at most one odd number. We first peel off all the parts that can form a 2 * 2 square, and the interior of this part can be 2 horizontal or 2 vertical. Leave it alone. Then count the number of additional rows. Judge the parity of the difference between the number of dominoes that can be placed in the extra row and the number of required dominoes. And the parity of the difference between the number of dominoes placed vertically and the number of dominoes that should be placed vertically. If both parts are even. Note that it can be placed. In fact, the extra rows or columns are divided for judgment. Think clearly, the code is very simple.

#include<bits/stdc++.h>
using namespace std;
int check(int x,int y)
{
	return y>=x&&(y-x)%2==0;
}
int main()
{
	int t,n,m,k;
	cin>>t;
	while(t--)
	{
		cin>>n>>m>>k;
		int cnt=(n/2)*(m/2);
		int h=0,v=0;
		if(n%2==1)h=(m/2);
		if(m%2==1)v=(n/2);
		if(check(h,k)&&check(v,(n*m)/2-k))
		 cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
	return 0;
 } 

D2.Domino (hard version)

The title of the hard version is the same as the first half. One more requirement is to construct the placement of the dominoes. The required character cannot cause ambiguity. We can have a greedy construction. Determine the placement of dominoes according to d1. Then it can form a 2 * 2 part to ensure that the adjacent horizontal and vertical are constructed in dictionary order. The extra rows or columns are placed above or to the left of the even part. The character is the character separated by 2 lines or 2 columns. Then it's finished. The specific writing method can refer to the code.

#include<bits/stdc++.h>
using namespace std;
int check(int x,int y)
{
	return y>=x&&(y-x)%2==0;
}
char ans[500][500];
int main()
{
	int t,n,m,k;
	cin>>t;
	while(t--)
	{
		memset(ans,0,sizeof(ans));
		cin>>n>>m>>k;
		int cnt=(n/2)*(m/2);
		int h=0,v=0;
		if(n%2==1)h=(m/2);
		if(m%2==1)v=(n/2);
		if(check(h,k)&&check(v,(n*m)/2-k))
		 {	
		    cout<<"YES"<<endl;
		    int dx=0,dy=0;
			if(n%2==1)
			{
				for(int i=0;i<m;i++)
				ans[0][i]='a'+(i/2*2+2)%26;
				dx=1;
			}
			if(m%2==1)
			{
				for(int i=0;i<n;i++)
				ans[i][0]='a'+(i/2*2+2)%26;
				dy=1;
			}
			int cnt=(k-h)/2;
			for(int i=dx;i<n;i+=2)
			for(int j=dy;j<m;j+=2){
				int tmp=(i-dx+j-dy)%26;
				char s1=tmp+'a',s2=tmp+1+'a';
				if(cnt)
				{
					ans[i][j]=ans[i][j+1]=s1;
					ans[i+1][j]=ans[i+1][j+1]=s2;
					cnt--;
				} 
				else
				{
					ans[i][j]=ans[i+1][j]=s1;
					ans[i][j+1]=ans[i+1][j+1]=s2; 
				}
			}
			for(int i=0;i<n;i++)
			cout<<ans[i]<<endl;
		}
		else cout<<"NO"<<endl;
	}
	return 0;
 } 

E. Fixed Points

This e-question requires deleting part of the score in a. The number of b[i]=i in the deleted array is k. Ask at least how many can be deleted.

In fact, this type of problem is easy to think of dynamic programming. It is difficult to enumerate the deletion process. There is no good greedy strategy. So obviously, we can only use dp to solve the problem. Then we first design the state transition equation of dp. We can define dp[i] [j] to represent the number of items in which b[i]=i can be satisfied by deleting j items in the first I items.

The transfer of the equation is also very simple. dp[i] [j] can be transferred from dp[i-1] [j-1] and dp[i-1] [j]. If we don't delete the new, we have to judge whether the newly added b[i] and (i-j) are equal. i-j here represents the position of the newly added number in the b array. If equal, + 1; If deleted, it is transferred from j-1. This item has been deleted. So no changes will be sent.

dp design is finished, and then enumerate from small to large. If you encounter the first dp[n] [i] greater than k, you can output it directly

#include<bits/stdc++.h>
using namespace std;
int a[2010],dp[2010][2010];//dp represents the maximum case that the first i number can be satisfied by deleting j
int main()
{
	int t,n,k;
	cin>>t;
	while(t--)
	{
		cin>>n>>k;
		for(int i=1;i<=n;i++)
			cin>>a[i];
			memset(dp,0,sizeof(dp));
			for(int i=1;i<=n;i++)
			{
				for(int j=0;j<=n;j++)
					dp[i][j]=dp[i-1][j]+(a[i]==(i-j));//Transfer without deletion of current item
				for(int j=1;j<=n;j++)
					dp[i][j]=max(dp[i][j],dp[i-1][j-1]);//Delete transfer of current item
			}
			int ans=n+1;
			for(int i=0;i<=n;i++)
				if(dp[n][i]>=k)//Judge to delete at least several items that can meet the requirements of the topic
				{
					ans=i;
					break;
				}
			if(ans==n+1)cout<<-1<<endl;
			else cout<<ans<<endl;
	}
	return 0;
}

F. Equidistant Vertices

This is a tree problem. It is asked to select k points and require their distance from the root node to be an equal constant. Ask how many options there are. Take the mold.

Then we can directly consider if k=2 Then any two points will do. In this case, a special judgment is made directly. Because the data range is relatively small. We can directly enumerate all points as root nodes. Then the node is counted as the root node, which is actually the number of root node LCA nodes with the same distance from the root node. Then enumerate the number of points at each depth. Select k points from n. This process can be solved by combinatorial number. However, the data range is not large. There's no need to push. Just put it directly into dp for statistics. The design here is to enumerate the number of each depth for the directly connected nodes of the root node, and then multiply it with dp[i-1] [j-1] to select the number of times before adding. Count all the answers directly. If you don't understand, you can see the comments of the code. Because there aren't many. There are no chained forward stars in the map. They are stored directly in the adjacency table. In fact, the efficiency is almost the same. This inscription adjacency table is much easier to write. It should be noted that. This method actually enumerates one more layer of depth. In fact, we can directly count the number of depths greater than u. Then save it and enumerate only this part. About 10 times faster. But the scope of this question is too small. I ran this enumeration depth code for 300ms. If you save it, you can run it in 30ms. If you are interested, you can try to write it yourself

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=105,mod=1e9+7;
ll ans,t,n,m,x,y,cnt,u[N][N],d[N],son[N],dp[N][N];
vector<int> G[N];
void dfs(int x,int fa,int col){
	d[x]=d[fa]+1;
	u[col][d[x]]++;
	for(auto y:G[x])if(y!=fa)dfs(y,x,col);
}
int main(){
	cin>>t;
	while(t--){
		cin>>n>>m,ans=0;
		for(int i=1;i<=n;++i)G[i].clear();
		for(int i=1;i<n;++i){
			cin>>x>>y;
			G[x].push_back(y);
			G[y].push_back(x);
		}
		if(m==2)//If any two points are satisfied, just make a special judgment directly
		{
			cout<<(n*(n-1)/2)<<endl;
			continue;
		}
		for(int i=1;i<=n;++i)//Enumerate root nodes
		{
			memset(u,0,sizeof(u));
			d[i]=cnt=0;
			for(auto y:G[i])
			{
				dfs(y,i,y);
				son[++cnt]=y;//Records the subtree of the current root node
			}
			for(int D=1;D<=n;++D)//Enumeration depth
			{
				memset(dp,0,sizeof(dp));
				dp[0][0]=1;
				for(int j=1;j<=cnt;++j){
					dp[j][0]=dp[j-1][0];
					for(int k=1;k<=j;++k)
						dp[j][k]=(dp[j-1][k-1]*u[son[j]][D]%mod+dp[j-1][k])%mod;
				}
				(ans+=dp[cnt][m])%=mod;
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

Topics: codeforce