# Educational Codeforces Round 108 (Rated for Div. 2)A~D

Posted by integravtec on Sun, 20 Feb 2022 08:12:36 +0100

Foreword: making A, B, D and C has been timeout, and I didn't think of how to optimize it.
Rating: 1153 + 146 -- > 1299 (green)
Don't talk about the problem, just talk about the solution and code.

A. Red and Blue Beans
topic type: greed
analysis: if r is less than B, try to replace 1 with more, so calculate the difference between r and B and see if the difference / D (rounded up) > = min (r, b).
code:

```#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int t,a,b,d;

int main()
{
ios::sync_with_stdio(false);
cin >> t ;
while(t--){
cin >> a >> b >> d ;
int cha = fabs(a-b);
int minn = min(a,b);
if(d == 0)
a == b ? (cout << "YES" << endl) : (cout << "NO" << endl) ;
else if( (cha%d==0 ? cha/d : cha/d+1) <= minn)
cout << "YES" << endl ;
else
cout << "NO" << endl ;
}
return 0;
}
```

B. The Cake Is a Lie
topic type: I don't know, conclusion?
analysis: through analysis, we can know that a position (i,j) can only be reached by (1,1) taking j-1 steps to the right and i-1 steps down. Therefore, no matter how you go, val(i,j) is fixed.
code:

```#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int t,n,m,k,dp;

int main()
{
ios::sync_with_stdio(false);
cin >> t ;
while(t--){
cin >> n >> m >> k ;
for(int i = 1 ; i <= n ; ++i)
for(int j = 1 ; j <= m ; ++j){
if(i>1)dp[i][j] = dp[i-1][j] + j;
if(j>1)dp[i][j] = dp[i][j-1] + i;
}
if(dp[n][m] == k)
cout << "YES" << endl ;
else
cout << "NO" << endl ;
}
return 0;
}
```

C. Berland Regional
topic type: data structure, greed, optimization
analysis: the initial idea is that we can save each student into a one-dimensional structure, which contains his school and skills. Then sort, the key words are school first, and then skills.

```int cmp(student &a1,student &a2){
if(a1.uid!=a2.uid)return a1.uid<a2.uid;
return a1.ski>a2.ski;
}
```

then, record the position of the first person in each university, first [], the number of people in each university, Num [], and record the prefix and pre []. When each team is limited to K, the total score of the ith university is: pre[first[i]+num[i]/k*k-1] - pre[first[i]-1]
Optimization: in this case, first enumerate k and then m universities, with a complexity of O(nm). If k is greater than the number of people in a certain university, the university will not participate in the statistics in the following k. We can skip it. So you can change the sorting keyword: first rank the number of universities, then rank the University id, and then rank the skills. In this way, universities with a small number of people are in the front. Define a pointer group now. When enumerating universities, start from now. If there are not enough people in a certain university, the pointer will jump back. It's much better in time.
code:

```#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define max_(a,b) a>b?a:b
using namespace std;

int t,n,sumu,num,u_first_stu,next_;
long long pre;

struct student
{
int uid,ski;
}stu;

int cmp(student &a1,student &a2)
{
///Number of first responders.
if(num[a1.uid] != num[a2.uid])return num[a1.uid] < num[a2.uid];
///Then go to college.
else if(a1.uid != a2.uid)return a1.uid < a2.uid;
return a1.ski > a2.ski;
}

int main()
{
ios::sync_with_stdio(false);
cin >> t ;
while(t--){
cin >> n ;
for(int i = 1 ; i <= n ; ++i)
cin >> stu[i].uid , num[stu[i].uid]++;
for(int i = 1 ; i <= n ; ++i)
cin >> stu[i].ski ;
sort(stu+1,stu+1+n,cmp);
stu.uid = 0;
for(int i = 1 ; i <= n ; ++i){
pre[i] = pre[i-1] + stu[i].ski;
if(stu[i].uid != stu[i-1].uid){
u_first_stu[stu[i].uid] = i;
next_[stu[i-1].uid] = stu[i].uid;
}
sumu = max_(sumu , stu[i].uid);
}
next_[stu[n].uid] = 0;
long long ans;
int fi , en , now = stu.uid;
for(int k = 1 ; k <= n ; ++k){
ans = 0;
for(int j = now ; j ; j = next_[j]){
if(k > num[j])(now = next_[j]);
else{
fi = u_first_stu[j];
en = fi + num[j]/k*k -1;
ans += (pre[en] - pre[fi-1]);
}
}
cout << ans << " " ;
}
cout << endl ;
for(int i = 1 ; i <= n ; ++i)
pre[i] = num[i] = u_first_stu[i] = 0;
for(int i = 0 ; i <= sumu ; ++i)
next_[i] = 0;
}
return 0;
}
```

D. Maximum Sum of Products
topic type: dp
analysis: in fact, no matter what topic, we should observe it from many aspects and find out the various properties of the topic, so as to find out the method and optimization.
first, there are two arrays a and b.
a: 1 2 3 4 5 6
b: 1 2 3 4 5 6
(i,j) is to invert the paragraph i to j in a.
so (3,4)
a: 1 2 4 3 5 6
b: 1 2 3 4 5 6
(2,5)
a: 1 5 4 3 2 6
b: 1 2 3 4 5 6
(1,6)
a: 6 5 4 3 2 1
b: 1 2 3 4 5 6
4 3 --> 5 4 3 2 --> 6 5 4 3 2 1
it can be found that the inverted large segment contains the previous small segment (partially the same), or the large segment can be transferred from the small segment. Then let DP [l] [R] be the answer obtained by inverting the paragraph l~r. dp[l][r] = dp[l+1][r-1] + a[r]*b[l] + a[l]*b[r]. Initialize the DP of length 1 and 2, and then record the prefix and. Complexity O(n*n).
code:

```#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define max_(a,b) a>b?a:b
using namespace std;

int t,n;
long long a,b;
long long ans,prefi,dp;

int main()
{
ios::sync_with_stdio(false);
cin >> n ;
for(int i = 1 ; i <= n ; ++i)
cin >> a[i] ;
for(int i = 1 ; i <= n ; ++i)
cin >> b[i] ;
for(int i = 1 ; i <= n ; ++i)
prefi[i] = prefi[i-1] + a[i]*b[i] , dp[i][i] = a[i]*b[i];
ans = prefi[n];
for(int len = 2 ; len <= n ; ++len){
for(int fi = 1 ; fi + len -1 <= n ; ++fi){
int en = fi + len -1 ;
if(len == 2)
dp[fi][en] = a[fi]*b[en] + a[en]*b[fi];
else
dp[fi][en] = dp[fi+1][en-1] + a[fi]*b[en] + a[en]*b[fi];
ans = max_(ans , prefi[n] - prefi[en] + prefi[fi-1] + dp[fi][en]);
}
}
cout << ans << endl ;
return 0;
}
```