洛谷p1769 DP(線段樹思想)

這題乍一看很嚇人,實則當你去手畫一下比賽過程的時候就可以知道了,假設總人數有8人,1, 2 , 3 , 4 , 5 , 6 ,7 ,8.
題目說了每一輪都是按編號順序從小到大去比賽的那麼第一輪就是(1,2),(3,4),(5,6),(7,8).這麼個比賽順序,第二輪就是(1,2)的勝利者去比(3,4)的勝利者(另外兩個同理)。這個比賽的過程在我剛剛接觸這個題的時候我想的是線段樹的過程,但是是一個十分完美的區間劃分,線段樹可能會有(1,3)區間去分開變成(1,2)和(3)的情況,但是這裏不會。利用線段樹的這個過程我們就可以十分完美的去模擬出這個比賽的過程。接下來考慮我們要怎麼得到答案,我先說我一開始想的錯誤的想法,我最初爲了避免小數運算,選擇了把勝率當做權值去做,90%概率我就拿90分,然後去計算每個人獲勝的總權值去比較大小,但是算權值的時候我用的也是加法,沒去想乘法,所以一頓瞎雞兒操作30分。。。。。
(暴躁改幾次還是沒用選擇打開了題解233333)正確的應該是這樣子的我們和線段樹一樣f[i],i這個節點就代表了一個區間範圍[L,R],然後我們在開一維度j表示這個區間內的勝者。f[i][j]的值就代表了j這個人在這個區間獲勝的概率。要怎麼算呢?首先j這個人是在左邊區間來的還是右邊區間來的我們可以知道,我們按他在左邊兒子(區間)來的,(在右邊的同理)。那麼這個j節點就是在[L , mid]的區間的勝者,我們用他這個節點是這個區間的勝者的概率f[i * 2][j]去與右區間的每一個勝者獲勝的概率去乘上j打贏他們的概率
f[i][j] = sum(f[i*2][j] * f[i * 2 + 1][k]),k就代表了右邊區間的所有可能獲勝的人。這個式子其實就是一個人在這個區間獲勝是概率是在原本所在區間獲勝的概率在去分別乘上要贏另一個區間那個獲勝的人的概率 在乘上另一個區間那個獲勝的人要在她所在原本區間要獲勝的概率,有點小饒,在多看兩遍。
這樣就做完收工了,最後統計[1,R]區間每個人的勝率去得答案就好了

#include<iostream>
#include<cstdio>
#include<stack>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#include<time.h>
#include<string>
#include<cmath>
#include <ctime>
#include<bitset>
#include <cctype>
#define debug cout<<"*********degug**********";
#define int long long
#define RE register
#define yn yn_
using namespace std;
const long long max_ = 1500 + 7;
const int mod = 1e9 + 7;
const int inf = 1e9;
const long long INF = 1e18;
int read() {
	int s = 0, f = 1;
	char ch = getchar();
	while (ch<'0' || ch>'9') {
		if (ch == '-')
			f = -1;
		ch = getchar();
	}
	while (ch >= '0'&&ch <= '9') {
		s = s * 10 + ch - '0';
		ch = getchar();
	}
	return s * f;
}
inline int min(int a, int b) {
	return a < b ? a : b;
}
inline int max(int a, int b) {
	return a > b ? a : b;
}
int quick_pow(int x, int n) {
	int res = 1;
	while (n > 0) {
		if (n & 1)	res = res * x;
		x = x * x ;
		n >>= 1;//相當於n=n/2.詳情請參考位移運算符。
	}
	return res;
}
int n, stander; double f[max_ * 4][max_], nodee[max_][max_];
void update(int node, int L, int R) {
	if (L == R) {
		f[node][L] = 1.0;
		return;
	}
	int mid = (L + R) / 2,L_tree = node * 2 , R_tree = node * 2 + 1;
	update(L_tree, L, mid); update(R_tree, mid + 1, R);
	for (int i = L; i <= mid; i++) {
		double t = 0.0;
		for (int j = mid + 1; j <= R; j++) {
			t =t +  f[R_tree][j] * nodee[i][j] * f[L_tree][i];
		}
		f[node][i] = t ;
	//	printf("[%d,%d]的%d取得勝利的分數:%d\n", L, R, i, f[node][i]);
	}
	for (int i = mid + 1; i <= R; i++) {
		double t = 0.0;
		for (int j = L; j <= mid; j++) {
			t += f[L_tree][j] * nodee[i][j] * f[R_tree][i];
		}
		f[node][i] = t ;
		//printf("[%d,%d]的%d取得勝利的分數:%d\n", L, R, i, f[node][i]);
	}
}

signed main() {
	n = read();
	stander = quick_pow(2, n);
	for (int i = 1; i <= stander; i++) {
		for (int j = 1; j <= stander; j++) {
			int t = read();
			nodee[i][j] = t / 100.0;
			//if (i != j && nodee[i][j] == 0)nodee[i][j] = -inf;
		}
	}
	update(1, 1, stander);
	double ansvalue = 0; int ans = 122345;
	for (int i = 1; i <= stander; i++) {
		if (f[1][i] > ansvalue) {
			ansvalue = f[1][i];
			ans = i;
		}
		else {
			if (f[1][i] == ansvalue && ans > i)ans = i;
		}
	}cout << ans;
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章