Educational Codeforces Round 117 (Rated for Div. 2)

Keywords: cf

Educational Codeforces Round 117 (Rated for Div. 2)

A. Distance

https://codeforces.com/contest/1612/problem/A

The conditions given in the title are

The distance is Manhattan distance, which is equivalent to step size.

From the half condition of the topic, we can get that the step size and are ab step size, and each step size is half of AB step size.

Therefore, it is obvious that:

\[1. If and are odd, they do not exist\ 2. If they are all even numbers, it is obvious that only half of the step size is required\ \]

//Original code
#include<bits/stdc++.h>
using namespace std;
int t;
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		if((x+y)%2!=0) printf("-1 -1\n");
		else if(x%2==0&&y%2==0) printf("%d %d\n",x/2,y/2);
		else if(x%2!=0&&y%2!=0) 
		{
			if(x>y) printf("%d %d\n",(x+y>>1)-y,y);
			else  printf("%d %d\n",x,(x+y>>1)-x);
		}
	}
	return 0;
}
//update
#include<bits/stdc++.h>
using namespace std;
int t;
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		int p=x+y,q=x/2;
		if(p%2!=0) printf("-1 -1\n");
		else printf("%d %d\n",q,p/2-q);
	}
	return 0;
}

B. Special Permutation

https://codeforces.com/contest/1612/problem/B

For the sequence with the title of 1-n, construct a double sequence with the length of n/2 to ensure that a is the smallest in the left half and b is the largest in the right half

So obviously we can construct it like this

a is placed in the front, and then the left half is the largest. Similarly, the right side

#include<bits/stdc++.h>
using namespace std;
int cnt,t,n,a,b;
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d%d",&n,&a,&b);
        int t=n/2;
        if(a==t+1&&b==t-1) {for(int i=a;i<=n;i++) printf("%d ",i);for(int i=b;i>=2;i--) printf("%d ",i);printf("1\n");}
        else if(a>t||b<t) puts("-1");
        else {for(int i=n,cnt=0;cnt==t;i--) if(i!=b) printf("%d%c",i,(++cnt==t?'\n':' '));for(int i=1,cnt=0;cnt==t;i++) if(i!=a) printf("%d%c",i,(++cnt==t:'\ ':' '));}
}

C. Chat Ban

https://codeforces.com/contest/1612/problem/C

The topic is a triangle structure, plus an arithmetic sequence, what is the number of the first column to exceed.

Just two points directly.

This is a very classic and obvious dichotomy. The dichotomy is very important in two parts, one is dichotomy, and the other is the check function.

If we get banned after yy messages, we also get banned after y+1y+1, y+2y+2 and so on messages (and vice versa, if we don't get banned after yy messages, we also don't get banned after y−1y−1, y−2y−2 and so on messages).

The structure of triangle is divided into two parts. One part is y < = k, which directly uses the summation formula of arithmetic sequence, and the other part is Y > k, which needs to use half plus arithmetic summation

Finally, the formula is obtained

\[y<=k \ \ \ cnt=\frac{n(n+1)}{2} \\ y> K \ \ \ \ CNT = the rest of CNT (k) + CNT (k-1) - CNT (2k-1-y) \]

Two points. Just find the first one > =

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
ll k,x,all;
int t;
ll get(int x){return  x*1ll*(x+1)/2;}
bool check(ll mid)
{
	if(mid<=k) return get(mid)>=x;
    else return (get(k)+get(k-1)-get(2*k-1-mid))>=x;
}
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%llu%llu",&k,&x);
		ll l=0,r=2*k-1;
		while(l<r)
		{
			ll mid=l+r>>1;
			if(check(mid)) r=mid;
			else l=mid+1;
		}
		printf("%llu\n",r);
	}
	return 0;
}

D. X-Magic Pair

https://codeforces.com/contest/1612/problem/D

A simple math problem

When you see the operation set =d, it is easy to find that this is a monotonic decreasing process. You must assign a distance to one of them, and there are no more than three relationships: greater than, less than, or equal to.

If it is assigned to a large one, the distance will become smaller. If it is assigned to a small one, the distance may become smaller or larger. If it is equal to 0, note that once it is 0, it will cycle directly. The distance is always equal to a value, and must be assigned to 1, then either 0, d, or d,d.

For the first two cases, if it is the first one, is it obviously like rolling division? But here it is more subtractive. Therefore, if x occurs in the process of subtracting the large from the small, it is true. Then it is equivalent to (b-x)% a==0

For the second case, if it is assigned to a small one, the second distance will become one of the previous a and B, so it must be assigned to one of them, and it will either change back to the original or become the case of case 1.

So to sum up: just simulate the process of rolling division, as long as it occurs in the monotonic decline process. At the same time, once it is 0, there will be a cycle. At this time, you can exit.

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a,b,x; 
int T;
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%lld%lld%lld",&a,&b,&x);
		bool flag=false;
		if(a>b) swap(a,b);
		if(a==x||b==x) {puts("YES");continue;}
		while(a!=0&&b!=0)
		{ 
			if((b-x)%a==0&&(b-x)>=0){puts("YES");flag=true;break;}
			else 
			{
				ll tmp=a;
				a=b%a,b=tmp;
			}
		}	
		if(!flag) puts("NO");
	}
	return 0;
 }

E. Messages

https://codeforces.com/contest/1612/problem/E

The title is about n students. Everyone reads k[i] letter, and then wants to read the m[i] letter. You can pin a pile of letters. Ask for expectation. This question gives me a new way to write probability questions.

\[E(x)=F_1+F_2+...+F_n,F_i is the situation that the ith person gets the letter\ We set \{c1,c2,c3,c4... \} for our pin letters\ F[i]=\begin{cases} 0 & if \ m[i] \notin C\\ 1 & if \ m[i]\in C \ and \ k[i]<=t\\ \frac{k[i]}{t} & if m[i]\ \in \ C \ and \ k[i]>t\\ \end{cases} \]

t is very small, only 20, and it is the same for parts greater than 20.

\[correctness of greed: because each letter corresponds to the situation of people and people are separated from each other, it is correct to choose as large as possible. \]

\[proof: because only 20 letters can be seen at most, their sum is the same, from large to small, or the 20 numbers, but some components that were originally 1 will become smaller. \]

Just enumerate.

Sort them from large to small, select the value of each one, and then select it from the bottom. Compare all the selections.

Time complexity O (n^2logn)

#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
const int N=2e5+52,K=20;
typedef long long ll;
typedef pair<int,int> PII;
int m[N],k[N],n; 
bool frac_greater(pair<int, int> a, pair<int, int> b)//Comparison mode 
{
    return a.first * b.second > a.second * b.first;
}
int main()
{
	scanf("%d",&n);
	for(int i=0;i<n;i++) scanf("%d %d",&m[i],&k[i]);//Everyone's situation, the first few letters, read k letters 
	vector<int> ans1;//Store everyone's information 
	PII ans2={0,1};//Storage results 
	for(int i=1;i<=K;i++)//Because the maximum is 20, the calculation of the excess 20 will be smaller, and the excess 20 is equal to 20
	{
		vector<int> score(N);//Open N bits, each bit is 0 
		for(int j=0;j<n;j++) score[m[j]]+=min(i,k[j]);//Get the situation of each letter. If this letter is selected (if it is selected, and the small is 1, otherwise it is k[j], and if it is not selected, it is 0) 
		vector<PII > val;//Bucket sorting 
		for(int j=0;j<N;j++) val.push_back({score[j],j});
		sort(val.rbegin(),val.rend());
		PII cur_ans={0,i};
		vector<int> lt;
		for(int j=0;j<i;j++)cur_ans.x+=val[j].x,lt.push_back(val[j].y);
		if(frac_greater(cur_ans,ans2)) ans2=cur_ans,ans1=lt;
	} 
	printf("%d\n",ans1.size());
	for(auto x:ans1) cout<<x<<" ";
	puts("");
	return 0;
 } 

F. Armor and Weapons

https://codeforces.com/contest/1612/problem/F

Question F is a greedy question. There are probably two things, and then reach the target point through some conditions.

First reaction: greedy, shortest path (I don't know why many problems can be directly linked to graph theory, or indirectly linked to graph theory. I've seen a lot in recent competitions), DP optimal solution.

Again, the edge weight is 1, BFS.

Then I took a look at tutorial. That's the good guy.

The only thing I didn't expect was to prove optimization.

If the direct BFS would be nm, this is unacceptable.

\[each time we exchange, we must exchange the largest one, because if we choose the small one in order to make up the combination, the updated one will be invalid or even worse, because it is equivalent to gaining + 1 around the long way\ Then in each layer, if x and y are less than or equal to another group, it must be invalid. \\ Then, add modifications to the original BFS, which is similar to the pruning of BFS. If it is less than or equal to, that is, redundancy is generated, then we will not use BFS \]

#include<bits/stdc++.h>

using namespace std;

int n, m;

#define x first
#define y second

typedef pair<int, int> comb;

comb norm(const comb& a)
{
    return make_pair(min(a.x, n), min(a.y, m));
}

bool good(const comb& a)
{
    return a.x == n || a.y == m;
}

bool comp(const comb& a, const comb& b)
{
    if(a.x != b.x)
        return a.x > b.x;
    return a.y > b.y;
}

int main()
{
    scanf("%d %d", &n, &m);
    int v;
    scanf("%d", &v);
    set<comb> s;
    for(int i = 0; i < v; i++)
    {
        int x, y;
        scanf("%d %d", &x, &y);
        s.insert(make_pair(x, y));
    }
    int steps = 0;
    vector<comb> cur;
    cur.push_back(make_pair(1, 1));
    while(true)
    {
        if(cur[0] == make_pair(n, m))
            break;
        vector<comb> ncur;
        for(auto x : cur)
        {
            int sum = x.x + x.y;
            if(s.count(x))
                sum++;
            comb z = x;
            z.x = sum;
            ncur.push_back(norm(z));
            z = x;
            z.y = sum;
            ncur.push_back(norm(z));
        }
        sort(ncur.begin(), ncur.end(), comp);
        int mx = 0;
        vector<comb> ncur2;
        for(auto x : ncur)
        {
            if(x.y <= mx) continue;
            mx = max(mx, x.y);
            ncur2.push_back(x);
        }
        cur = ncur2;
        steps++;
    }
    printf("%d\n", steps);
}

#include <bits/stdc++.h>
using namespace std;
const int LOG = 30;
int main(){
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  int n, m;
  cin >> n >> m;
  int q;
  cin >> q;
  vector<int> a(q), b(q);
  for (int i = 0; i < q; i++){
    cin >> a[i] >> b[i];
    a[i]--;
    b[i]--;
  }
  if (n > m){
    swap(n, m);
    for (int i = 0; i < q; i++){
      swap(a[i], b[i]);
    }
  }
  set<pair<int, int>> st;
  for (int i = 0; i < q; i++){
    st.insert(make_pair(a[i], b[i]));
  }
  vector<int> dp(n, -1);
  dp[0] = 0;
  int ans = 0;
  while (true){
    ans++;
    vector<int> dp2(n, -1);
    for (int i = 0; i < n; i++){
      if (dp[i] != -1){
        if (st.count(make_pair(i, dp[i])) == 0){
          int x = min(i + dp[i] + 1, m - 1);
          dp2[i] = max(dp2[i], x);
          int y = min(i + dp[i] + 1, n - 1);
          dp2[y] = max(dp2[y], dp[i]);
        } else {
          int x = min(i + dp[i] + 2, m - 1);
          dp2[i] = max(dp2[i], x);
          int y = min(i + dp[i] + 2, n - 1);
          dp2[y] = max(dp2[y], dp[i]);
        }
      }
    }
    if (dp2[n - 1] == m - 1){
      cout << ans << endl;
      break;
    }
    swap(dp, dp2);
  }
}


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
using namespace std;
set<pair<int,int> > st;
int n,m,q;
inline int query(int u,int v)
{
	return u+v+(st.find(make_pair(u,v))!=st.end());
}
int G(int x,int y)
{
	x=min(x,n),y=min(y,m);
	if(x==n&&y==m) return 0;
	int q=query(x,y);
	if(x==n) return G(x,q)+1;
	if(y==m) return G(q,y)+1;
	if(x>y) return G(x,q)+1;
	return G(q,y)+1;
}
int F(int x,int y)
{
	x=min(x,n),y=min(y,m);
	if(x==n&&y==m) return 0;
	int q=query(x,y),ans=0;
	if(x==n) return F(x,q)+1;
	if(y==m) return F(q,y)+1;
	if(x>y)
	{
		ans=F(x,q);
		if(x-y<=5) ans=min(ans,F(q,y));
		else ans=min(ans,G(q,y));
		return ans+1;
	}
	else
	{
		ans=F(q,y);
		if(y-x<=5) ans=min(ans,F(x,q));
		else ans=min(ans,G(x,q));
		return ans+1;
	}
}
int main()
{
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=q;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		st.insert(make_pair(u,v));
	}
	printf("%d\n",F(1,1));
	return 0;
}

G. Max Sum Array

https://codeforces.com/contest/1612/problem/G

Consider the contributions of the outermost two. Finish one group at a time, cut off the front suffix and continue.

Here are some proofs

\[the outermost two have the largest number\ Greedy perturbation method + counter evidence method to prove:\ The contribution of C {E1} is (C {E1} - 1) * (n-1). Take any point, i-1+n-i=n-1. If there are C {E1} points, the final result is (C {E1} - 1) * (n-1)\ Let C {EK} be the first one greater than C {E1}, and the contribution of C {EK} will increase (C {EK} - 1) * (p-1), because there is no same as him in the front, and C {E1} is divided into two parts, one is\ (p, n] - DEC1 = C {E1} [p + 1, n] ⋅ (p − 1) the other part is (1,p). Since it is from the left to the right, there will be a change in the relative relationship \ \ however, we can still get the result through estimation, dec2 ≤ C {E1} [2, p − 1] ⋅ (p − 1). Here, on the one hand, it is zoom, on the other hand, it is convenient for merging\ inc − dec ≥ (p − 1) ⋅ (C {EK} − C {E1}) > 0 proves that our swap selection is better. Therefore, the largest must be placed outside\ In fact, we can also get such a conclusion intuitively. For any group of points, we must want to maximize its contribution, and the more numbers involved \ \ the greater the overall change will be driven by its change. Therefore, we must let such points be processed first and at the same time\ Quantity is also required in the title. It is easy to think of permutations and combinations\ This makes us think about how to arrange when we have multiple sets of the same maximum values. Obviously, their arbitrary arrangement is correct. Here we give proof\ set \ l_i,r_i are the left and right endpoints of the points we are dealing with. You can get that contri is (C {ei} − 1) ⋅ (r_i − l_i), and \ Sigma_{i=1}^k(c_{ei}−1)⋅(r_i−l_i) =\ (c_{e1}−1)(∑_{i=1}^kri−∑_{i=1}^kl_i) = (c_{e1}−1)((n−k)k+k(k+1)2−k(k+1)2)=(c_{e1}−1)k(n−k)\ Where did the formula on the right come from? You can use the pigeon nest principle, because it is placed symmetrically on the left and right, and the space size is just right, then it will spread over all numbers. So the summation formula. \Then you only need to perform such steps below\ Find the maximum value -- if it is 1, Num is 0; Otherwise, add the contribution, and num multiplies their arrangement \ \ because the left and right sides are separated, and must be one on the left and one on the right, so num multiplies {k!}^2\ After execution, remove the two numbers and update the information at the same time. Repeat the operation\ If the last is 1, then multiply it directly by a factorial. \Care must be taken to prevent plastic overflow \Time complexity O(n+C) \]

#include<bits/stdc++.h>
#define rep(i,l,r) for(int i=int(l);i<int(r);i++)
#define rep2(i,l,r) for(int i=int(l);i>int(r);i--)
#define x first
#define y second 
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=1e6+52,mod=1e9+7;
template<class A, class B> ostream& operator <<(ostream& out, const pair<A, B> &p) {
    return out << "(" << p.x << " " << p.y << ")";
}
template<class A> ostream& operator <<(ostream& out, const vector<A> &v) {
    rep(i, 0, sz(v)) {
        if(i) out << " ";
        out << v[i];
    }
    return out;
}
ll m;
ll fact[N],cnt[N];
ll total,ans_sum,ans_num=1;
void init()
{
	fact[0]=1;
	for(int i=1;i<N;i++) fact[i]=fact[i-1]*1ll%mod*i%mod;
} 
int main()
{
	init();
	scanf("%lld",&m);
	rep(i,0,m) 
	{
		ll x;scanf("%lld",&x);
		cnt[x]++;total+=x;
	}
	rep2(i,N-50,1)//Shaping overflow 
	{
		ans_num=(ans_num%mod*(fact[cnt[i]]%mod*fact[cnt[i]]%mod)%mod)%mod;
		ans_sum=(ans_sum +(((i - 1)*cnt[i]%mod)*((total - cnt[i]) % mod)%mod))%mod;
		total-=2*cnt[i],cnt[i-2]+=cnt[i];
	}
	ans_num=(ans_num*fact[cnt[1]])%mod;
	cout<<ans_sum<<" "<<ans_num<<'\n';
	return 0;
}

Here's what the boss thinks

Here is a slightly different approach for problem G which I think is easier. (Sorry if my explanation is not good.) It would seem that many other people have this approach too.

First, let's ask ourselves, given an array, how can we find the total sum of distances between all pairs of equal elements? For each element, we will need to add to the answer the sum of absolute values between each pair of indexes where it exists. This is a very well known problem, and can be easily understood by looking at an example.

Let's say an element exists at the indices [1,4,5,6,8][1,4,5,6,8]. Then, we will need to add (4−1)+(5−1)+(6−1)+(8−1)+(5−4)+(6−4)+(8−4)+(6−5)+(8−5)+(8−6)(4−1)+(5−1)+(6−1)+(8−1)+(5−4)+(6−4)+(8−4)+(6−5)+(8−5)+(8−6) to the answer. Overall, 1 has been subtracted 4 times, 4 has been subtracted twice, 5 does not contribute towards the sum, 6 is added twice, and 8 is added 4 times. So we will add to the sum (−4)∗1+(−2)∗4+(0)∗5+(2)∗6+(4)∗8(−4)∗1+(−2)∗4+(0)∗5+(2)∗6+(4)∗8. In general, for a sorted array [p1,p2,...,px][p1,p2,...,px], we will add to the answer p1∗(1−x)+p2∗(3−x)+p3∗(5−x)+...+px∗(x−1)p1∗(1−x)+p2∗(3−x)+p3∗(5−x)+...+px∗(x−1). We can think of this as assigning multiplying each index by a coefficient and finding the total sum of indexes, such that the coefficients assigned to indexes with the same element are a [1−x,3−x,...,x−1][1−x,3−x,...,x−1] in ascending order.

We can now move on to maximising the answer. We will generate a coefficient array. For each cici, we will add the elements [1−ci,3−ci,...,ci−1][1−ci,3−ci,...,ci−1] to the coefficient array. Then, we want to obtain a permutation of this coefficient array [p1,p2,...,pn][p1,p2,...,pn] such that ∑ni=1ipi∑i=1nipi is maximised. By the rearrangement theorem, this sum is maximised when pp is sorted, and it is easy to see that such a permutation is possible.

For more clarity, consider the case where c=[3,3,2]c=[3,3,2]. We will generate the coefficient array [−2,0,2]+[−2,0,2]+[−1,1]=[−2,−2,−1,0,0,1,2,2][−2,0,2]+[−2,0,2]+[−1,1]=[−2,−2,−1,0,0,1,2,2]. Then the maximum answer will be (−2)∗0+(−2)∗1+(−1)∗2+(0)∗3+(0)∗4+(1)∗5+(2)∗6+(2)∗7=27(−2)∗0+(−2)∗1+(−1)∗2+(0)∗3+(0)∗4+(1)∗5+(2)∗6+(2)∗7=27, and this is achievable for example by choosing a=[1,2,3,1,2,3,1,2]a=[1,2,3,1,2,3,1,2].

Now, how do we do this fast? Instead of actually generating the coefficient array, we will simply create a frequency map storing how many times each element exists in the coefficient array. We can create this map quickly using a difference array (or you can visualise this as a sweepline). We will then iterate through this map in ascending order. For each element ee which occurs numnum times in the coefficient array, we will assign ee as the coefficient of the numnum lowest indexes which we haven't assigned yet, and increment our answer by (e∗e∗ sum of chosen indexes). Remember that of the distinct elements in aa, exactly numnum of these elements will have contributed ee to the coefficient array, so these indexes will correspond to some permutation of these numnum elements in aa. We will therefore multiply the number of possible arrays by num!num!, as this is the number of permutation of these numnum elements in aa.

See https://codeforces.com/contest/1612/submission/136599117 for implementation details. If an array is used instead of a map, the overall complexity of this algorithm is O(m+max(ci))O(m+max(ci)).

Posted by josh_mcqueen on Mon, 06 Dec 2021 11:32:45 -0800