The 45th international undergraduate Programming Competition (ICPC) Asian regional competition (Nanjing)

Keywords: Algorithm

E Evil Coordinate

Simulation + thinking

Here's a question for you U L R D ULRD ULRD is a string of four characters, U U U stands for walking up L L L left R R R right D D D down, then give the point ( x , y ) (x,y) (x,y) let you judge whether it is possible for the robot to carry out this series of operations without passing through points in the diagram ( x , y ) (x,y) (x,y) output path if possible, output if impossible I m o p s s i b l e Imopssible Imopssible

Idea: enumerate the full arrangement in four directions and avoid it if possible ( x , y ) (x,y) (x,y) then the robot must be able to choose one direction first and go straight before going the other direction. The code is as follows:

#include<bits/stdc++.h>

using namespace std;

int mx, my;

bool get_p(int u, int r, int d, int l, int a[]){
	string res = "";
	for(int i = 0; i < 4; ++ i)
		if(a[i] == 1)
			while(u --) res += 'U';
		else if(a[i] == 2)
			while(r --) res += 'R';
		else if(a[i] == 3)
			while(d --) res += 'D';
		else while(l --) res += 'L';
	
	bool flag = true;
	int sx = 0, sy = 0;
	for(int i = 0; i < res.size(); ++ i){
		if(res[i] == 'L') sx --;
		else if(res[i] == 'R') sx ++;
		else if(res[i] == 'D') sy --;
		else sy ++;
		
		if(sx == mx && sy == my){
			flag = false;
			break;
		}
	}
	
	if(flag){
		cout << res << endl;
		return true;
	}
	return false;
	
}

int main(){
	int T;
	cin >> T;
	
	while(T --){
		cin >> mx >> my;
		
		string s;
		cin >> s;
		
		int l, r, u, d;
		l = r = u = d = 0;
		
		int sx = 0, sy = 0; //Less than 0 left and lower, more than 0 right and upper 
		 
		for(int i = 0; i < s.size(); ++ i)
			if(s[i] == 'L') l ++, sx --;
			else if(s[i] == 'R') r ++, sx ++;
			else if(s[i] == 'D') d ++, sy --;
			else u ++, sy ++;
			
		if(mx == 0 && my == 0) puts("Impossible");
		else if(mx == sx && my == sy) puts("Impossible");
		else{
			bool flag = false;
			int a[5] = {1, 2, 3, 4};
			do{
				if(get_p(u, r, d, l, a)){
					flag = true;
					break;
				}
			}while(next_permutation(a, a + 4));
			
			if(!flag) puts("Impossible");
		}
	}
	
	return 0;
}

F,Fireworks

Probability, expectation, three points

Meaning: K o t o r i Kotori Kotori sets off fireworks. It takes him a lot of money to make a fireworks n n It takes n minutes to set off all these fireworks m m m minutes, the probability of releasing perfect fireworks is p p p let you expect to release a perfect fireworks

Idea: at least let go x x It takes x times to release the perfect fireworks n x + m nx+m nx+m, let the probability of not releasing perfect fireworks be q = 1 − p q=1-p q=1 − p, release x x The probability that x fireworks have at least one perfect fireworks is 1 − q x 1-q^x 1 − qx, the expectation is 1 1 − q x \frac{1}{1-q^x} 1 − qx1, so the expected number of times is f ( x ) = n x + m 1 − q x f(x)=\frac{nx+m}{1-q^x} f(x)=1 − qxnx+m. it can be found that this is a concave function, that is, the peak value can be calculated by three points. The code is as follows

#include<bits/stdc++.h>

using namespace std;

const double eps = 1e-6;

double n, m;
double p;

double f(int x){
	return (n * x + m) / (1 - pow(1 - p, x));
}

int main(){
	int T;
	cin >> T;
	
	while(T --){
		cin >> n >> m >> p;
		
		p /= 10000;
		int l = 0, r = 1e9;
		
		while(l <= r){
			int ml = l + (r - l) / 3, mr = r - (r - l) / 3;
			if(f(ml) >= f(mr)) l = ml + 1;
			else r = mr - 1;
		}
		printf("%.10lf\n", f(r));
	}
	
	return 0;
}

K,K Co-prime Permutation

thinking

Here are two numbers n n n and k k k. I want you to find a sequence: this sequence is 1 ∼ n 1\sim n 1 ∼ n arrangement with k k The number of k is satisfied g c d ( a i , i ) = 1 gcd(a_i,i)=1 gcd(ai, i)=1. If the sequence satisfying the condition is not found, it will be output − 1 -1 −1

thinking k = 0 k=0 Output when k=0 − 1 -1 − 1, because 1 1 The greatest common divisor of 1 and any number is 1 1 1. If it is an odd number 1 1 1 keep still every exchange a i a_i ai} and a i + 1 a_{i+1} ai+1} switching k / 2 k/2 k/2 pair, if k k If k is an even number, then from 1 1 1 start each exchange a i a_i ai} and a i + 1 a_{i+1} ai+1} switching k / 2 k/2 k/2 pair. principle g c d ( i , i + 1 ) = 1 gcd(i,i+1)=1 gcd(i,i+1)=1

The code is as follows

#include<bits/stdc++.h>
using namespace std;

const int N = 1e6 + 10;

int n, k;
int a[N];

int main(){
    
    cin >> n>> k;
    for(int i = 1; i <= n; ++ i) a[i] = i;
    if(k == 0) puts("-1");
    else{
        int cnt = 1;
        if(k % 2) cnt ++;
        k /= 2;
        for(; k > 0 && cnt <= n; cnt += 2, -- k) swap(a[cnt], a[cnt + 1]);
        for(int i = 1; i <= n; ++ i) cout << a[i] << ' ';
        puts("");
    }
    
}

L,Let's Play Curling

Dichotomy + thinking

Summary of the meaning of the topic: the red stone with the most scores between the two blue stones is the one with the most scores. It is directly sorted by two points. However, it is necessary to judge the one before the first blue stone and the one after the last blue stone (just set up two Sentinels directly)

The code is as follows

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5, INF = 2e9;

int n, m;
int a[N], b[N];

void solve(){
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
	for(int i = 1; i <= m; ++ i) scanf("%d", &b[i]);
	sort(a + 1, a + n + 1);
	sort(b + 1, b + m + 1);
	int res = 0;
	b[0] = -INF, b[m + 1] = INF;
	for(int i = 0; i <= m; ++ i){
		int l = upper_bound(a + 1, a + n + 1, b[i]) - a;
		int r = lower_bound(a + 1, a + n + 1, b[i + 1]) - a - 1;
		res = max(res, r - l + 1);
	}
	if(!res) puts("Impossible");
	else printf("%d\n", res);
}

int main(){
	
	int T; scanf("%d", &T);
	while(T --){
		solve();
	}
	
	return 0;
}

M,Monster Hunter

Tree DP

Meaning: fight monsters. The blood volume of each monster is h p i hp_i hpi, you have to 1 1 Start playing at point 1, that is, the root node. You need to kill his father node before playing a monster. The price of killing a monster is the cost of the monster itself h p + hp+ hp + all sons directly connected to the monster h p hp hp. Now you have a kind of magic. Beating a monster can not consume any energy, so you can find out what you have 0 , 1 , 2 , . . . , n 0,1,2,...,n 0,1,2,..., the energy consumed in n magic (magic has been used before hitting monsters)

Idea: tree DP, backpack on tree
state d p [ u ] [ i ] [ 0 / 1 ] dp[u][i][0/1] dp[u][i][0/1] represents the node u u The subtree with u as the root has i i i sons are not magic, node u u u used / not used magic

Transfer:
f [ u ] [ j + k ] [ 0 ] = m i n ( f [ u ] [ j + k ] [ 0 ] , f [ u ] [ j ] [ 0 ] + m i n ( f [ v ] [ k ] [ 0 ] , f [ v ] [ k ] [ 1 ] ) ) f[u][j + k][0]=min(f[u][j+k][0],f[u][j][0]+min(f[v][k][0],f[v][k][1])) f[u][j+k][0]=min(f[u][j+k][0],f[u][j][0]+min(f[v][k][0],f[v][k][1]))
f [ u ] [ j + k ] [ 1 ] = m i n ( f [ u ] [ j + k ] [ 1 ] , f [ u ] [ j ] [ 1 ] + m i n ( f [ v ] [ k ] [ 0 ] , f [ v ] [ k ] [ 1 ] + a [ v ] ) ) f[u][j + k][1]=min(f[u][j+k][1],f[u][j][1]+min(f[v][k][0],f[v][k][1]+a[v])) f[u][j+k][1]=min(f[u][j+k][1],f[u][j][1]+min(f[v][k][0],f[v][k][1]+a[v]))

code:

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int N = 2e3 + 10;

int n;
int h[N], e[N], ne[N], idx;
ll f[N][N][2]; //Node i has j child nodes alive. Is node i alive 
ll a[N];
int sz[N];

void add(int a, int b){
	e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

void dfs(int u){
	f[u][0][0] = 0;
	f[u][1][1] = a[u];
	sz[u] = 1;
	for(int i = h[u]; ~i; i = ne[i]){
		int v = e[i];
		dfs(v);
		for(int j = sz[u]; j >= 0; -- j)
			for(int k = sz[v]; k >= 0; -- k){
				f[u][j + k][0] = min(f[u][j + k][0], f[u][j][0] + min(f[v][k][0], f[v][k][1]));
				f[u][j + k][1] = min(f[u][j + k][1], f[u][j][1] + min(f[v][k][0], f[v][k][1] + a[v]));
			}
		sz[u] += sz[v];
	}
}

int main(){
	
	int T; cin >> T;
	while(T --){
		cin >> n;
		memset(h, -1, sizeof h);
		for(int i = 0; i <= n; ++ i)
			for(int j = 0; j <= n; ++ j)
				f[i][j][0] = f[i][j][1] = 1e18;
		for(int i = 2, x; i <= n; ++ i){
			cin >> x;
			add(x, i);
		}
		for(int i = 1; i <= n; ++ i) cin >> a[i];
		dfs(1);
		for(int i = n; i >= 0; -- i) cout << min(f[1][i][0], f[1][i][1]) << ' ';
		puts("");
	}
	
	return 0;
}

Posted by sliilvia on Tue, 19 Oct 2021 11:28:00 -0700