題解 BJOI2019 奧術神杖

2022-05-01 19:39:11 字數 1427 閱讀 9706

題目傳送門

給出乙個殘缺的字串,每個位置都 \(\in[0,9]\)。有 \(m\) 中貢獻,即 \(s,k\),表示該字串中沒出現一次 \(s\),貢獻便乘上 \(k\)。最後對貢獻求 \(c\) 次根,其中 \(c\) 是總出現次數。求貢獻的最大值。

字串長度以及貢獻字串長度之和 \(\le 1500\)

首先你需要想到我們可以全部取 \(\ln\),然後每次貢獻就是 \(+k\),求根就是 \(/c\),於是問題就是最大化:

\[\frac

\]然後你對這個二分,判斷條件就是:

\[\sum_>0

\]於是我們可以在 ac 自動機上進行dp,即設 \(f_\) 表示到第 \(i\) 個字串對應自動機上狀態j時的最大貢獻,轉移顯然。

於是,我們就可以在 \(nl\log w\) 的時間複雜度內解決這個問題。

#include using namespace std;

#define int register int

#define maxn 2005

template inline void read (t &t)while (c >= '0' && c <= '9') t *= f;}

template inline void read (t &t,args&... args)

template inline void write (t x)if (x > 9) write (x / 10);putchar (x % 10 + '0');}

int n,m;

int g[maxn][maxn][2];

double dp[maxn][maxn];

char s1[maxn],s2[maxn],ans[maxn];

struct auto

sum[now] ++,val[now] += v;

} void build ()

} } double work (double v)

}for (int i = 0;i <= cnt;++ i) val[i] += sum[i] * v;

int pos = 0;for (int i = 0;i <= cnt;++ i) if (dp[n][i] > dp[n][pos]) pos = i;

for (int i = n,now = pos;i;-- i) ans[i] = g[i][now][0] + '0',now = g[i][now][1];

return dp[n][pos];

}}t;

signed main()

t.build();

double l = 0,r = 1e9;

while (r - l > 1e-3)

t.work(l),printf ("%s",ans + 1);

return 0;

}

BJOI2019 奧術神杖

傳送門 首先w1w2 w3 w nn sqrt n nw1 w2 w3 wn 可以利用對數轉化 l og 2w1w 2w3 wnn 1n l og2w ilog 2 frac sum log 2 w i log2 n w1 w 2 w3 wn n 1 l og2 wi 那麼令ti log2 wi t...

BJOI2019 奧術神杖

傳送門 根據題意,需要知道神杖所包含了哪些咒語,大可使用自動ac自動機。關鍵是如何處理 sqrt c 這其實也很套路,一眼看過去,覺得根號這個東西顯然就不可做,於是想辦法消去根號。於是對於這個式子取對數,sqrt c frac magic v 1 v 2 v n 對於 frac 這種形式的答案,很顯...

BJOI2019 光線 遞推

題目鏈結 令 f i 表示光線第一次從第一塊玻璃射出第 i 塊玻璃的比率。令 g i 表示光線射回第 i 塊玻璃,再射出第 i 塊玻璃的比率。容易得到 beginf i f a i f b ig i g i b a i b b ig i a g a i a g b ig i end 對於 2 式,移...