Codeforces round #735 (Div. 2)

A. Cherry

B. Cobb

C. Mikasa

D. Diane

E. You

A. Cherry

analysis:
This problem needs to find the maximum value of the value obtained by multiplying the maximum value in a certain interval by the minimum value in the whole array range. We record that the maximum value obtained by multiplying the maximum value by the minimum value in a certain interval is rmq; Suppose we consider three adjacent numbers a[i] and a[i+1] and a[i+2] (the interval considered at this time is [i,i+2]), and calculate that the rmq of the interval is ANS. We decompose the interval into two intervals [i,i+1] and [i+1,i+2]. The rmq of interval 1 is r1 and the rmq of interval 2 is r2; So what is the relationship between ANS and r1 and r2? Obviously, ans==max(r1,r2). Why? Because of the size relationship of three numbers, there are six possibilities (we remember a[i]=a, a[i+1]=b, a[i+2]=c):

  1. A max, b middle, c Min: ans==a*b;
  2. A max, b min, c middle: ans==a*b
  3. A middle, b max, c Min: ans==a*b;
  4. a middle, B min, c max: ans==b*c;
  5. a min, B middle, c max: ans==b*c;
  6. a min, B max, c middle: ans==b*c;
    It can be seen that the interval maximum value rmq must be taken between two adjacent numbers, so you only need to traverse the array once, find the product of all adjacent numbers, and compare the maximum value.
    Efficiency: the time complexity is O(n)
    Note: to use long long, 1e6 * 1e6 is beyond the int range after all

AC Code:

#include<iostream>
using namespace std;
const int N=2e5+5;
int main(){
	int t;
	cin>>t;
	while(t--){
	   long long int ans=0;	
	   int n;
	   int a[N];
	   cin>>n;
	   for(int i=1;i<=n;i++)
		cin>>a[i];
		for(int i=2;i<=n;i++)
		if((1LL*a[i]*a[i-1])>ans) ans=1LL*a[i]*a[i-1];	
		cout<<ans<<endl;
	}
	return 0;
} 

B. Cobb

analysis:
If you carefully observe the range of K, you will find that K < = 100; Obviously, 1 < = AI < = n, so AI | AJ < = 2 * n. The maximum of i * j can reach n^2, and the maximum of k*(ai | aj) is 200*n; Obviously, when n is a certain size, 200*n does not play a great role. You only need to traverse all n when n is a certain size. Where should this certain large area be? We remember that the function f (i, J) = i * j-k*(ai | aj). Then f(n-1,n)=n * n-2 * k * n-n. We need to find the possible minimum i so that f (i, J) > F (n-1, n). Assuming ai=an=0, then f(i,n)=i * n (at this time, i must be the minimum, because the subtracted k*(ai | aj) is 0 and j is the maximum n). Then let i * n > n * n-2 * k * N-N;
Then i > n-2 * k-1. So we just need to traverse i from max(1,n-2 * k) to get the answer.
Efficiency: the time complexity is O(k^2)
AC Code:

#include<bits/stdc++.h>
using namespace std;
const long long INF=1e12;
const int maxn=2e5+10;
int n,k,a[maxn];
inline int read(){
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
	return x*f; 
}
inline long long f(int i,int j){
	return 1LL*i*j-1LL*k*(a[i]|a[j]);
} 
int main(){
	int t;t=read();
	while(t--){
		memset(a,0,sizeof(a));
		n=read(),k=read();
        for(int i=1;i<=n;i++) a[i]=read();
        long long ans=-INF;
        int i,j;
		i=max(1,n-2*k);
        for(;i<=n;i++)
           for(j=i+1;j<=n;j++)
           ans=max(ans,f(i,j));
        printf("%lld\n",ans);
	}
	return 0;
} 

C. Mikasa

analysis:
Since T < = 30000, m < = 1e9; Obviously, direct violence will definitely timeout. At this time, we need to think carefully. Do we have to traverse each number? Obviously not. Before you think of a good method, you have to know one thing: n^x=k, then n ^ k=x (^ is XOR). This problem requires us to find the smallest non negative integer ans, which does not appear in n ^x (x belongs to 0~ m). That is, let's find a minimum K so that n ^ k > m; Because when n ^ k < = m (remember k = = n ^x), the K has already appeared in n ^x. So we can get the minimum K satisfying the condition, that is, the answer ans, by comparing each binary digit of N and m+1. So how should we compare? First, understand the formula we need to compare n ^ k > = m, that is, the result of N and the minimum K XOR is greater than or equal to m+1. Then we can traverse each digit from the highest bit to the lowest bit. First of all, we should know that the 30th power of 2 is just greater than 1e9, which satisfies the condition. Therefore, we start from i=30 to i=0, and then compare the I + 1st binary number of N and m+1 (because when i=0, it is the first binary number); There are three cases for comparison: suppose that the i+1 binary of n is a and the i+1 binary of m+1 is b. (a,b can only be equal to 0 or 1)

  1. a==b: at this time, the binary numbers of these two bits are equal. In order to minimize k, we let the i+1 binary number of k be 0. Because if a=b=1,a^0=1=b; Otherwise, a=b=0;a ^ 0=0=b.
  2. a=0,b=1: at this time, in order to make n ^ k > = m+1; The high bit binary of n ^ k should be greater than or equal to m+1. Therefore, the binary bit of K can only be equal to 1. So a ^1=b.
  3. a=1,b=0: at this time, the binary bit of K can be either 0 or 1 (because a ^ 1 (or 0) > = b). However, since it is traversed from the high bit, in order to minimize K, only k=0 can be made. At this time, we can clearly find that all binary numbers of n ^k before this bit are equal, and this bit is n ^k = 1 > = m+1 = 0. Because this is a high bit, no matter what the next binary is, n ^k must be greater than or equal to m+1. So you can jump out of the loop and let the binary number of k after it be all 0, that is, the minimum value of K.
    Efficiency: the time complexity is O(1). Isn't it incredible!!!
    Note: for each binary digit, use (x > > I) & 1 instead of just n > > I. Because the value of N > > I is the sum of the values of i+1 bits and all previous binary digits. With (x > > I) & 1, you can only judge whether this bit is 0 or 1

AC Code:

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
	return x*f; 
}
int main(){
    int t=read();
	while(t--){
		int n=read(),m=read();
		if(m<n) {
			printf("0\n");
			continue;
		}
		++m;
		int ans=0;
		for(int i=30;i>=0;i--){ //Binary starts processing from high order 
			if((n>>i&1)==(m>>i&1)) continue;
			else if(!(n>>i&1)&&(m>>i&1)) ans+=(1<<i);
			else break;
		}
		printf("%d\n",ans);
	}	
	return 0;
} 

D. Diane

analysis:
This is obviously a problem of finding rules and then constructing strings. Then finding the law becomes the key and difficult point. Next, let's see what rules can be found through the meaning of the question! We need to make all the possible occurrences of the same substring odd, so let's think about what happens when the occurrence of substrings is odd? First of all, we need to construct the string ourselves, so try to make the constructed string simple. The fewer letters we use, the better. We assume that the string pp is all the letter A. if the string length is k, then f(a)=k; f(aa)=k-1; f(aaa)=k-2; … (f(i) represents the number of occurrences of substring i in the string); Assuming that the string qq is all letter A and the string length is k-1, then f(a)=k-1; f(aa)=k-2; f(aaa)=k-3…; Then, for the long string pp+qq, assuming that the number of occurrences of each substring (a,aa,aaa or aaaa, etc.) in the string pp is x, then it is x-1 in qq; Because x+x-1=2*x-1; It must be odd. So the law has been found.
We only need to divide each string with length n into three parts. The left is k=n/2, all letters a, and the right is k-1=n/2-1, all letters a; The middle length is len=n-2*k+1. Then when n is an odd number, len=2; Just add bc; When n is an even number, len=1; Just fill b.
Efficiency: the time complexity is O(n)
Note: when n=1, output any letter separately; Otherwise, it will treat n as an odd number, and adding bc is beyond the range of n

The AC code is as follows:

#include<bits/stdc++.h>
using namespace std;
int main(){
	int t;cin>>t;
	while(t--){
		int n;cin>>n;
		int l=n/2,r=l-1;
		if(n==1) cout<<"a";
		else if(n&1){
			for(int i=1;i<=l;i++) cout<<"a";
			cout<<"bc";
			for(int i=1;i<=r;i++) cout<<"a";
		}
		else{
			for(int i=1;i<=l;i++) cout<<"a";
			cout<<"b";
			for(int i=1;i<=r;i++) cout<<"a";
		}
		cout<<endl;
	}
	return 0;
} 

E. You

analysis:
Konjac konjac konjac konjac konjac konjac konjac konjac konjac konjac konjac konjac konjac konjac konjac konjac konjac konjac konjac konjac konjac konjac konjac konjac konjac!!! However, when konjac gathered the thoughts of many big men, it finally cleared the clouds and saw the light. First, it should be a very basic operation to store the undirected edge of the tree with the adjacency table. This problem requires the number of times when gcd(a1,a2,..., an)=k from each value k of 1~n, that is, the number of different sequences. Then we need to find some rules, otherwise we can't start. We can open an ans[maxn] array. ans[i] records the number of times gcd(a1,a2,..., an) is a multiple of I. Why do you do this? After reading the following analysis, you will understand. We can find that the tree has n-1 edges, and each edge is connected with two nodes u,v; There are two cases of Decentralization: if node u is deleted first, decentralization a[u]+1; Otherwise, it is a[v]+1; Therefore, it is not difficult to find that each edge has two cases, so the total number of cases is 2^(n-1). And because 1 must be a factor of any integer (Note: gcd (0, x) = x); So ans[1]=2^(n-1).
For others, k > 1; So what is the situation?
Carefully observe that for each decentralization sequence a1,a2,..., an, since only n-1 edges contribute to the decentralization, and each edge contributes 1, a1+a2 +... + an=n-1; Then, when k > 1, K is the common factor of a1,a2,..., an only when all ai (i=1,2,..., n) can divide K. So all ai can divide K, that is, a1+a2 +... + an can divide K; So at this point n-1 can also divide K. Then there are two situations:

  1. (n-1)%k!=0: at this time, there must be ai that cannot divide K completely; Therefore, gcd(a1,a2,..., an) cannot be equal to the multiple of K, that is, ans[k]==0.
  2. (n-1)%k==0: judgment is required at this time. Judge whether each ai is a multiple of K, because their sum is a multiple of K, but each ai is not necessarily a multiple of K. At this time, you can use dfs deep search to search all nodes of the tree from node 1, and first search all leaf nodes of the tree, and then backtrack and judge step by step. There are also many cases of judgment:
    1: For the edge of leaf node V (whose father is u), its decentralization must be assigned to point U; If point v is assigned, then point v is deleted first and then point u is deleted; At this time, a[v]=1; Then a[v] cannot be a multiple of K (k > 1).
    2: For the edge of non leaf node V (the father is u): if a[v]%k = =0, that is, the weight distribution of node V is already a multiple of K, then the weight distribution of the edge must be given to node u; That is, delete node u first and then node V; If at this time a[v]%k= 0, then the decentralization of the edge must be given to node V, that is, delete node V first and then delete node u; But now a[v]%k= 0; That is, the decentralization of node V cannot be equal to the multiple of K, then you can jump out of the deep search, and ans[k]=0; Otherwise, if a[v]%k = =0, continue to search deeply until all nodes meet a[i]%k==0; At this point, ans[k]=1. Think about it. Why is ans[k] = =1? In fact, the principle is very simple. Looking back at the backtracking process of deep search, you will find that after the above analysis, the decentralization of each side is actually fixed to a certain point without selection. That is, the decentralization of each point is fixed, that is, the order of deleting all nodes is fixed, so the deletion order is unique, so ans[k]=1.

Now that the ans[maxn] array has been processed, there is only one last thing left, that is to find the answer. We can find that for k=2 and k=4, if gcd(a1,a2,..., an)==4, then it is for k=2; There is also contribution, that is, for a number k, ans[k] contributes to all the factors of K, so the factor of K needs to subtract the contribution of K. We can traverse n~1 with I in reverse order; Find all its multiples j (j=2i,3i,..., until j < = n), and then ans[i]-ans[j]. The final ans array records the answers we need.
Efficiency: the time complexity is O(nlogn+n*f(n-1)). f(n-1) is the number of factors of n-1. O(n*f(n-1)) is required for judgment and dfs when creating ans [] array; The process of finding the answer at the end requires O(nlogn).

The AC code is as follows:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
const int maxn=2e5+10;
int n,ans[maxn],dp[maxn];
int flag;
vector<int>g[maxn];
inline int read(){
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
	return x*f;
}
void Init(){
	for(int i=1;i<=n;i++) dp[i]=ans[i]=0,g[i].clear();
}
int quick_power(ll base,int power){
	ll res=1;
	while(power){
		if(power&1) res=(res*base)%mod;
		power>>=1;
		base=(base*base)%mod;
	}
	res%=mod;
	return (int)res;
}
void dfs(int u,int fa,int k){
	for(int i=0;i<g[u].size();i++){
		if(!flag) return ;
		int v=g[u][i];
		if(v==fa) continue;
		dfs(v,u,k);
		if(dp[v]%k){
			dp[v]++;
			if(dp[v]%k) flag=0;
		}
		else dp[u]++;
	}
}
int main(){
	int t=read();
	while(t--){
		n=read();
		Init();
		for(int i=1;i<n;i++){
			int u=read(),v=read();
			g[u].push_back(v);
			g[v].push_back(u);
		}
		ans[1]=quick_power(2,n-1);
		for(int i=2;i<=n;i++){
			if((n-1)%i!=0) continue;
			flag=1;
			dfs(1,0,i);
			ans[i]=flag;
			memset(dp,0,sizeof(dp));
		}
		for(int i=n;i>=1;i--){
			if((n-1)%i!=0) continue;
			for(int j=2*i;j<=n;j+=i) ans[i]=(ans[i]-ans[j]+mod)%mod;
		}
		for(int i=1;i<=n;i++) printf("%d ",ans[i]);
		printf("\n");
	}
	return 0;
} 

Tags: C++ Algorithm Dynamic Programming

Posted on Sat, 25 Sep 2021 21:24:25 -0400 by jrose83