I tried solving the problems from NWERC 2017 to practice.
A. Ascending Photo
When given an array of numbers, we want to cut it into some pieces, then rearrange the pieces so that the numbers are increasing. We want to find the minimum number of cuts needed to achieve this.
To start off, compress all unique heights to a range of
If all numbers are unique, we must cut whenever
Let
If
The case where
Finding all
code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<double,double> pdd;
typedef complex<double> cpx;
#define fastio cin.tie(0)->sync_with_stdio(0); cout.tie(0);
#define all(x) x.begin(),x.end()
#define compress(x) x.erase(unique(all(x)),x.end())
#define ff first
#define ss second
ll n,a[1000010],b[1000010],cnt[1000010];
ll dp[1000010],yes[1000010];
int main(){
fastio;
cin >> n;
vector<ll> cp;
for(int i=1;i<=n;i++){
cin >> a[i];
cp.push_back(a[i]);
}
sort(all(cp));
compress(cp);
for(int i=1;i<=n;i++){
a[i] = lower_bound(all(cp),a[i])-cp.begin()+1;
}
ll t = 1;
for(int i=1;i<=n;i++){
if(a[i]!=a[i-1]) b[t++] = a[i];
}
n = t-1;
vector<pll> v;
for(int i=1;i<=n;i++){
cnt[b[i]]++;
v.push_back({b[i],i});
if(b[i-1]+1==b[i]) yes[b[i]]++;
}
sort(all(v));
ll mt = 0, mx1 = 0, mx2 = 0, pr = 1;
ll tm = 0, tm1 = 0, tm2 = 0;
for(auto i:v){
if(i.ff!=pr){
mt = tm;
mx1 = tm1;
mx2 = tm2;
tm = 0; tm1 = 0; tm2 = 0;
}
if(i.ff==1){
dp[i.ss] = 0;
}
else{
if(cnt[i.ff]==1){
if(b[i.ss-1]==i.ff-1) dp[i.ss] = max(dp[i.ss],dp[i.ss-1]+1);
dp[i.ss] = max(dp[i.ss],mt);
ll k = dp[i.ss];
tm = max(tm,k);
if(b[i.ss+1]==i.ff+1){
if(tm1<k){
tm2 = tm1;
tm1 = k;
}
else if(tm2<k){
tm2 = k;
}
}
}
else{
dp[i.ss] = max(dp[i.ss],mt);
if(b[i.ss-1]==i.ff-1&&dp[i.ss-1]==mx1){
if(yes[i.ff]>1) dp[i.ss] = max(dp[i.ss],mx2+1);
}
else if(b[i.ss-1]==i.ff-1){
if(yes[i.ff]>1) dp[i.ss] = max(dp[i.ss],mx1+1);
}
else{
if(yes[i.ff]>0) dp[i.ss] = max(dp[i.ss],mx1+1);
}
ll k = dp[i.ss];
tm = max(tm,k);
if(b[i.ss+1]==i.ff+1){
if(tm1<k){
tm2 = tm1;
tm1 = k;
}
else if(tm2<k){
tm2 = k;
}
}
}
}
pr = i.ff;
}
// for(int i=1;i<=n;i++){
// cout << dp[i] << " ";
// }
// cout << "\n";
cout << n-1-tm << "\n";
}
B. Boss Battle
We blow up a bomb which destroys three consecutive pillars. After that, the boss moves to an adjacent pillar. We need to find the minimum number of bombs to defeat the boss in the worst case scenario.
We blow up a bomb. 3 consecutive pillars are destroyed. It is possible for the boss to move to the 2 pillars at each end, meaning we know for sure the boss is not in the middle destroyed pillar. Blow up 3 again, and this time there are 4 destroyed pillars. The boss can move to the 2 pillars at the end, meaning that the boss is definitely not in the middle 2. Continuing we know that every time we blow up a bomb we can increase 1 pillar where the boss is definitely not in. When 3 pillars are left, we can kill boss. Therefore the answer is
code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<double,double> pdd;
typedef complex<double> cpx;
#define fastio cin.tie(0)->sync_with_stdio(0); cout.tie(0);
#define all(x) x.begin(),x.end()
#define compress(x) x.erase(unique(all(x)),x.end())
#define ff first
#define ss second
int main(){
fastio;
ll n; cin >> n;
cout << max(1LL,n-2) << "\n";
}
C. Connect the Dots
Did not solve yet.
D. Dunglish
Given a sentence and a list of correct and incorrect translations for each word, find the number of correct and incorrect translations possible. If only one possible translation exists, output that translation.
For a word
In case the number of translations is 1, just save all the translations in any way, and output it.
code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<double,double> pdd;
typedef complex<double> cpx;
#define fastio cin.tie(0)->sync_with_stdio(0); cout.tie(0);
#define all(x) x.begin(),x.end()
#define compress(x) x.erase(unique(all(x)),x.end())
#define ff first
#define ss second
ll n,m;
string st[30];
map<string,ll> cr,icr;
map<string,string> mst;
int main(){
fastio;
cin >> n;
for(int i=1;i<=n;i++){
cin >> st[i];
}
cin >> m;
for(int i=0;i<m;i++){
string x,y,z; cin >> x >> y >> z;
mst[x] = y;
if(z=="correct") cr[x]++;
else icr[x]++;
}
ll cnt = 1, cor = 1;
for(int i=1;i<=n;i++){
cnt *= (cr[st[i]]+icr[st[i]]);
cor *= cr[st[i]];
}
if(cnt>1){
cout << cor << " correct\n";
cout << cnt-cor << " incorrect";
}
else{
ll f = 1;
for(int i=1;i<=n;i++){
cout << mst[st[i]] << " ";
if(icr[st[i]]) f = 0;
}
cout << "\n";
if(f) cout << "correct";
else cout << "incorrect";
}
}
E. English Restaurant
Did not solve yet.
F. Factor-Free Tree
Given an array, find a binary tree where a number is written on each node, and the preorder of the binary tree results in the given array. In addition, the number written on a node must be coprime with the numbers written on all of its ancestors.
A subtree represents some consecutive subarray. Also, the root of the tree must be coprime to all of the nodes. Therefore, given a range
Factorize all numbers. Then by looking at each factor, we can quickly find some
However, simply looping through
code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<double,double> pdd;
typedef complex<double> cpx;
#define fastio cin.tie(0)->sync_with_stdio(0); cout.tie(0);
#define all(x) x.begin(),x.end()
#define compress(x) x.erase(unique(all(x)),x.end())
#define ff first
#define ss second
const int MAX = 1e7+1;
int c[10000001];
vector<int> id[10000000];
int n,a[1000001];
int ans[1000001];
int chk(int k, int l, int r){
int li = -1, ri = 1e9;
for(int j=a[k];j>1;){
int p = c[j];
int idx = lower_bound(all(id[p]),k) - id[p].begin();
if(idx>0) li = max(li,id[p][idx-1]);
if(idx<(int)id[p].size()-1) ri = min(ri,id[p][idx+1]);
while(j%p==0) j /= p;
}
if(li<l&&ri>r) return 1;
else return 0;
}
int solve(int s, int e, int p = 0){
if(s>n||s<1||e>n||e<1||s>e) return 1;
int ret = 0;
for(int i=s,j=e;i<=j;i++,j--){
if(chk(i,s,e)){
ret = i;
break;
}
if(chk(j,s,e)){
ret = j;
break;
}
}
if(!ret) return 0;
ans[ret] = p;
return solve(s,ret-1,ret)&&solve(ret+1,e,ret);
}
int main(){
fastio;
iota(c,c+MAX,0);
for(int i=2;i<MAX;i++){
if(c[i]==i){
for(int j=i+i;j<MAX;j+=i){
c[j] = min(c[j],i);
}
}
}
cin >> n;
for(int i=1;i<=n;i++){
cin >> a[i];
for(int j=a[i];j>1;){
int k = c[j];
id[k].push_back(i);
while(j%k==0) j /= k;
}
}
int k = solve(1,n);
if(!k) cout << "impossible";
else{
for(int i=1;i<=n;i++){
cout << ans[i] << " ";
}
}
}
G. Glyph Recognition
For a given set of points find the regular polygon that results in the highest score.
It is possible to binary search. For each regular polygon, binary search for the side length
code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<double,double> pdd;
typedef complex<double> cpx;
#define fastio cin.tie(0)->sync_with_stdio(0); cout.tie(0);
#define all(x) x.begin(),x.end()
#define compress(x) x.erase(unique(all(x)),x.end())
#define ff first
#define ss second
const double PI = atan2(0,-1);
ll n;
vector<pll> v;
double ccw(pdd a, pdd b, pdd c){
double k = (b.ff-a.ff)*(c.ss-a.ss)-(b.ss-a.ss)*(c.ff-a.ff);
if(k>1e-6) return 1;
else if(k<-1e-6) return -1;
else return 0;
}
ll cnt(double r, ll x){
vector<pdd> pol;
double ang = 0;
for(int i=0;i<x;i++){
pol.push_back({r*cos(ang),r*sin(ang)});
ang += 2*PI/x;
}
ll ret = 0;
for(auto i:v){
ll f = 1;
for(int j=0;j<x;j++){
ll k = ccw(i,pol[j],pol[(j+1)%x]);
if(k<0) f = 0;
}
ret += f;
}
return ret;
}
double score(ll x){
double r1 = 0;
double lo = 0, hi = 1e7;
while(hi-lo>1e-7){
double m = (lo+hi)/2;
ll tmp = cnt(m,x);
if(tmp>0){
hi = m;
}
else{
r1 = max(r1,lo);
lo = m;
}
}
double r2 = 1e10;
lo = 0, hi = 1e7;
while(hi-lo>1e-7){
double m = (lo+hi)/2;
ll tmp = cnt(m,x);
if(tmp==n){
r2 = min(r2,hi);
hi = m;
}
else{
lo = m;
}
}
//cout << r1 << " " << r2 << "\n";
double a1 = x*r1*r1*sin(2*PI/x);
double a2 = x*r2*r2*sin(2*PI/x);
return a1/a2;
}
int main(){
fastio;
cin >> n;
for(int i=0;i<n;i++){
ll x,y; cin >> x >> y;
v.push_back({x,y});
}
double ns = -1;
ll ans = -1;
for(int i=3;i<=8;i++){
double k = score(i);
if(k>ns){
ns = k;
ans = i;
}
}
cout << setprecision(10);
cout << fixed << ans << " " << ns;
}
H. High Score
Given
If the minimum is large enough, it’s best to just add everything to the maximum. Otherwise, brute force by making the minimum into some number, then adding all leftovers to the maximum.
code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<double,double> pdd;
typedef complex<double> cpx;
#define fastio cin.tie(0)->sync_with_stdio(0); cout.tie(0);
#define all(x) x.begin(),x.end()
#define compress(x) x.erase(unique(all(x)),x.end())
#define ff first
#define ss second
ll n;
void solve(){
vector<ll> v;
for(int i=0;i<3;i++){
ll x; cin >> x;
v.push_back(x);
}
ll t; cin >> t;
sort(all(v));
if(v[0]>(ll)1e6){
cout << v[0]*v[0]+v[1]*v[1]+(v[2]+t)*(v[2]+t)+7*v[0] << "\n";
}
else{
ll ans = v[0]*v[0]+v[1]*v[1]+(v[2]+t)*(v[2]+t)+7*v[0];
for(int i=1;i<=(ll)1e7;i++){
if(v[0]>i) continue;
ll tmp = 0, tv[3] = {v[0],v[1],v[2]};
if(v[0]<i) tv[0] = i, tmp += i-v[0];
if(v[1]<i) tv[1] = i, tmp += i-v[1];
if(v[2]<i) tv[2] = i, tmp += i-v[2];
if(tmp>t) break;
ll k = t-tmp;
//cout << v[0] << " " << v[1] << " " << v[2] << "\n";
ans = max(ans,tv[0]*tv[0]+tv[1]*tv[1]+(tv[2]+k)*(tv[2]+k)+7*i);
}
cout << ans << "\n";
}
}
int main(){
fastio;
cin >> n;
for(int i=0;i<n;i++){
solve();
}
}
I. Installing Apps
To download an app you need
Sort the apps in order of
code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<double,double> pdd;
typedef complex<double> cpx;
#define fastio cin.tie(0)->sync_with_stdio(0); cout.tie(0);
#define all(x) x.begin(),x.end()
#define compress(x) x.erase(unique(all(x)),x.end())
#define ff first
#define ss second
struct Data{
ll ff,ss,i;
};
ll n,m,dp[510][10010],mp[510];
Data a[510];
pll tr[510][10010];
int main(){
fastio;
cin >> n >> m;
for(int i=1;i<=n;i++){
cin >> a[i].ff >> a[i].ss;
a[i].i = i;
}
sort(a+1,a+1+n,[&](Data x, Data y){
return x.ss-x.ff<y.ss-y.ff;
});
for(int i=1;i<=n;i++){
mp[i] = a[i].i;
}
for(int i=1;i<=n;i++){
for(int j=m;j>=0;j--){
dp[i][j] = dp[i-1][j];
tr[i][j] = {i-1,j};
if(j<a[i].ss) continue;
if(a[i].ff>a[i].ss&&m-(j-a[i].ss)>=a[i].ff){
ll k = dp[i-1][j-a[i].ss]+1;
if(k>dp[i][j]){
dp[i][j] = k;
tr[i][j] = {i-1,j-a[i].ss};
}
}
else if(a[i].ff<=a[i].ss){
ll k = dp[i-1][j-a[i].ss]+1;
if(k>dp[i][j]){
dp[i][j] = k;
tr[i][j] = {i-1,j-a[i].ss};
}
}
}
}
ll ri = n, rj = 0, ans = -1;
for(int i=0;i<=m;i++){
if(dp[n][i]>ans){
ans = dp[n][i];
rj = i;
}
}
cout << ans << "\n";
vector<ll> ret;
while(ri!=0||rj!=0){
ll ni = tr[ri][rj].ff;
ll nj = tr[ri][rj].ss;
if(nj!=rj){
ret.push_back(ri);
}
ri = ni; rj = nj;
}
reverse(all(ret));
for(auto i:ret){
cout << mp[i] << " ";
}
}
J. Juggling Troupe
Given an array consisting of values of
Think of the problem when there is only one
It is possible to see that we can look at all
Finally, for each index from
K. Knockout Tournament
Find the maximum probability which the first player can win by ordering the players in some way.
Lets say there are some dummy players with rating 0 so that the number of players is a power of 2. It is obvious that it is best to order the players in order of their rating (so that the highest 2 goes together and so on) and put player 1 at the end (with the lowest rating) to maximize the probability of winning.
Let
code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<double,double> pdd;
typedef complex<double> cpx;
#define fastio cin.tie(0)->sync_with_stdio(0); cout.tie(0);
#define all(x) x.begin(),x.end()
#define compress(x) x.erase(unique(all(x)),x.end())
#define ff first
#define ss second
ll n,a[5010],b[5010];
double p[5010][20];
int main(){
fastio;
cin >> n;
for(int i=0;i<n;i++){
cin >> a[i];
}
sort(a+1,a+n);
ll tmp = 1, cnt = 0;
while(tmp<n){
tmp *= 2;
cnt += 1;
}
ll r = tmp-n;
for(int i=0;i<r;i++){
b[2*i] = a[i];
b[2*i+1] = 0;
}
ll t = 2*r;
for(int i=r;i<n;i++){
b[t] = a[i];
t++;
}
for(int i=0;i<tmp;i++){
ll t = i/2;
p[i][1] = 1.0*b[2*t+i%2]/(b[2*t]+b[2*t+1]);
}
ll tr = 2;
for(int i=2;i<=cnt;i++){
tr *= 2;
for(int j=0;j<tmp;j++){
if(b[j]==0) continue;
double pr = 0;
ll gr = j/tr;
for(int k=gr*tr;k<(gr+1)*tr;k++){
if(k/(tr/2)==j/(tr/2)) continue;
pr += p[k][i-1]*b[j]/(b[j]+b[k]);
}
p[j][i] = pr*p[j][i-1];
}
}
// for(int i=0;i<tmp;i++){
// for(int j=1;j<=cnt;j++){
// cout << p[i][j] << " ";
// }
// cout << "\n";
// }
cout << setprecision(10);
cout << fixed << p[0][cnt];
}