周末狂欢赛3(跳格子,英雄联盟,排序问题)
文章目錄
- T1:跳格子
- 題目
- 題解
- CODE
- T2:英雄聯(lián)盟
- 題目
- 題解
- CODE
- T3:排序問題
- 題目
- 題解
- CODE
T1:跳格子
題目
n 個(gè)格子排成一列,一開始,你在第一個(gè)格子,目標(biāo)為跳到第 n 個(gè)格子。在每個(gè)格子 i 里面你可以做出兩個(gè)選擇:
選擇「a」:向前跳 ai 步。
選擇「b」:向前跳 bi 步。
把每步的選擇寫成一個(gè)關(guān)于字符 a 和 b的字符串。求到達(dá)格子 n 的方案中,字典序最小的字符串。當(dāng)做出某個(gè)選擇時(shí),你跳出了這n個(gè)格子的范圍,則這個(gè)選擇是不合法的。
當(dāng)沒有合法的選擇序列時(shí),輸出 No solution!
當(dāng)字典序最小的字符串無限長時(shí),輸出 Infinity!
否則,輸出這個(gè)選擇字符串
輸入格式
輸入有三行。
第一行輸入一個(gè)整數(shù)n
第二行輸入 n 個(gè)整數(shù),分別表示 ai
第三行輸入 n 個(gè)整數(shù),分別表示 bi
輸出格式
輸出一行字符串表示答案。
樣例
樣例輸入
7
5 -3 6 5 -5 -1 6
-6 1 4 -2 0 -2 0
樣例輸出
abbbb
數(shù)據(jù)范圍與提示
1≤n≤1051≤n≤10^51≤n≤105
?n≤ai,bi≤n-n≤a_i,b_i≤n?n≤ai?,bi?≤n
題解
其實(shí)不用太害怕,我們先打個(gè)暴力試試水,發(fā)現(xiàn)最傻的暴力都有80,我們就可以知道這道題很簡單
這道題后面的分?jǐn)?shù)來自于Infinity!Infinity!Infinity!的判斷,剛開始讀完題后可能大多數(shù)人是無法理解這句話的
我們來想想什么情況下會(huì)無限死循環(huán)。這個(gè)就要與字典序掛鉤了,字典序并不先比較長度,用過字典的吧!
在此題中只要對于iii位而言,只要填aaa后面的字符串的字典序一定小于填bbb
所以看一下這個(gè)神奇的栗子:
我們會(huì)從1選a跳到2再選a跳到4最后選b就可以跳到n了,答案是aab
但是我們發(fā)現(xiàn)如果跳到4后可以選擇一次a回到2,再從2回到4,最后選b到n,答案變成aaaab
根據(jù)字典序第三位一個(gè)是a,一個(gè)是b,a所在的字符串字典序較小,以此類推,我們的答案就可以變成aaaaaaa…b
顯然中間的a越多,字典序越小,這就是Infinity!Infinity!Infinity!的輸出
但不僅僅是這么簡單,如果是這樣子的栗子:
我們的答案是aaa,但是這里面仍然有循環(huán)出現(xiàn),跳到格子4后,選擇b跳回2,但是我們發(fā)現(xiàn)這只會(huì)讓答案變成aabbb…ba,第三位比較就知道字典序大于了aaa,所以這種循環(huán)的出現(xiàn)我們是可以輸出最后答案字符串的
因此我們來思考一下如何辨別這種情況,用一個(gè)手打隊(duì)列記錄下我們一路上的選擇,
假設(shè)1代表選a,0代表選b。在最后走到格子n的時(shí)候,就模擬一下這一路上的跳躍過程,
發(fā)現(xiàn)如果在跳躍的某一個(gè)點(diǎn)時(shí)選擇a會(huì)跳到已經(jīng)跳過的點(diǎn)上并且按照我們的答案存取發(fā)現(xiàn)這個(gè)點(diǎn)應(yīng)該選b才能保證后面能跳到最后格子時(shí)就意味著死循環(huán)出現(xiàn)了
否則仍然有解
CODE
#include <cstdio> #include <cstring> using namespace std; #define MAXN 100005 int n, idx; int a[MAXN], b[MAXN], st[MAXN]; bool vis[MAXN]; bool flag;void dfs ( int id ) {if ( flag )return;if ( id > n || id < 1 )return;if ( vis[id] )return;vis[id] = 1;if ( id == n ) {flag = 1;memset ( vis, 0, sizeof ( vis ) );int t = 1;vis[1] = 1;for ( int i = 1;i <= idx;i ++ ) {if ( st[i] )t = t + a[t];else {if ( t + a[t] > 0 && t + a[t] <= n && vis[t + a[t]] ) {printf ( "Infinity!" );return;}t = t + b[t];vis[t] = 1;}}for ( int i = 1;i <= idx;i ++ )printf ( "%c", st[i] ? 'a' : 'b' );return;}st[++ idx] = 1;dfs ( id + a[id] );idx --;st[++ idx] = 0;dfs ( id + b[id] );idx --; }int main() {scanf ( "%d", &n );for ( int i = 1;i <= n;i ++ )scanf ( "%d", &a[i] );for ( int i = 1;i <= n;i ++ )scanf ( "%d", &b[i] );dfs ( 1 );if ( ! flag )printf ( "No solution!" );return 0; }T2:英雄聯(lián)盟
題目
正在上大學(xué)的小皮球熱愛英雄聯(lián)盟這款游戲,而且打的很菜,被網(wǎng)友們戲稱為「小學(xué)生」。
現(xiàn)在,小皮球終于受不了網(wǎng)友們的嘲諷,決定變強(qiáng)了,他變強(qiáng)的方法就是:買皮膚!
小皮球只會(huì)玩 N\text{N}N 個(gè)英雄,因此,他也只準(zhǔn)備給這 N\text{N}N 個(gè)英雄買皮膚,并且決定,以后只玩有皮膚的英雄。
這 N\text{N}N個(gè)英雄中,第 i\text{i}i 個(gè)英雄有 KiK_iKi?款皮膚,價(jià)格是每款 CiC_iCi?Q 幣(同一個(gè)英雄的皮膚價(jià)格相同)。
為了讓自己看起來高大上一些,小皮球決定給同學(xué)們展示一下自己的皮膚,展示的思路是這樣的:對于有皮膚的每一個(gè)英雄,隨便選一個(gè)皮膚給同學(xué)看。
比如,小皮球共有 5 個(gè)英雄,這 5 個(gè)英雄分別有 0,0,3,2,4\text{0,0,3,2,4}0,0,3,2,4 款皮膚,那么,小皮球就有 3×2×4=243 \times 2 \times 4 = 243×2×4=24 種展示的策略。
現(xiàn)在,小皮球希望自己的展示策略能夠至少達(dá)到 \text{M}M 種,請問,小皮球至少要花多少錢呢?
輸入格式
第一行,兩個(gè)整數(shù) N,M\text{N,M}N,M
第二行,N\text{N}N個(gè)整數(shù),表示每個(gè)英雄的皮膚數(shù)量 KiK_iKi?
第三行,\text{N}N 個(gè)整數(shù),表示每個(gè)英雄皮膚的價(jià)格 CiC_iCi?
輸出格式
一個(gè)整數(shù),表示小皮球達(dá)到目標(biāo)最少的花費(fèi)。
輸入輸出樣例
輸入
3 24
4 4 4
2 2 2
輸出
18
說明/提示
樣例解釋
每一個(gè)英雄都只有4款皮膚,每款皮膚2Q幣,那么每個(gè)英雄買3款皮膚,3×3×3≥243 \times 3 \times 3 \ge 243×3×3≥24,共花費(fèi) 6×36 \times 36×3 Q幣。
數(shù)據(jù)范圍
共 10 組數(shù)據(jù),第 i\text{i}i組數(shù)據(jù)滿足:N≤max?(5,log24i)\text{N} \le \max(5, log_2^4i)N≤max(5,log24?i)
100%\text{100}\%100% 的數(shù)據(jù):M≤1017,1≤Ki≤10,1≤Ci≤199\text{M} \le 10^{17}, 1 \le K_i \le 10, 1 \le C_i \le 199M≤1017,1≤Ki?≤10,1≤Ci?≤199保證有解
題解
這是一道水水的dpdpdp,看都看的出來
從最簡單的二維dp搞起:
設(shè)dp[i][j]dp[i][j]dp[i][j]表示前i種皮膚共花費(fèi)j元的最大的不同種展示策略數(shù),
dp[i][j]=max(dp[i][j],dp[i?1][j?ci?p]?p),(p∈[1,ki])dp[i][j]=max(dp[i][j],dp[i-1][j-c_i*p]*p),(p∈[1,k_i])dp[i][j]=max(dp[i][j],dp[i?1][j?ci??p]?p),(p∈[1,ki?])
我們發(fā)現(xiàn)這個(gè)轉(zhuǎn)移式的第一維只跟上一次的dpdpdp有關(guān),我們就可以考慮滾動(dòng)(我就是這么寫的)
dp[f][j]=max(dp[f][j],dp[!f][j?ci?p]?p),(f=0/1,p∈[1,ki])dp[f][j]=max(dp[f][j],dp[!f][j-c_i*p]*p),(f=0/1,p∈[1,k_i])dp[f][j]=max(dp[f][j],dp[!f][j?ci??p]?p),(f=0/1,p∈[1,ki?])
當(dāng)然滾動(dòng)也能被壓成一維
dp[j]=max(dp[j],dp[j?ci?p]?p)dp[j]=max(dp[j],dp[j-c_i*p]*p)dp[j]=max(dp[j],dp[j?ci??p]?p)
要注意要從大到小,因?yàn)橐玫缴弦淮蔚那懊娴?span id="ozvdkddzhkzd" class="katex--inline">dpdpdp,如果我們先更新了小的,后面更新大的的時(shí)候會(huì)產(chǎn)生錯(cuò)誤
CODE
#include <cstdio> #include <cstring> #include <iostream> using namespace std; #define MAXN 305 #define MAXM 600005 #define LL long long int n; LL m, sum; LL dp[2][MAXM], k[MAXN], c[MAXN];int main() {scanf ( "%d %lld", &n, &m );for ( int i = 1;i <= n;i ++ )scanf ( "%lld", &k[i] );for ( int i = 1;i <= n;i ++ ) {scanf ( "%lld", &c[i] );sum += k[i] * c[i];}for ( int i = 0;i <= sum;i ++ )dp[0][i] = dp[1][i] = 1;int f = 0;for ( int i = 1;i <= n;i ++ ) {f = ! f;for ( int j = c[i];j <= sum;j ++ ) {dp[f][j] = dp[!f][j];//記得初始化for ( int p = 1;p <= k[i];p ++ ) {if ( j < p * c[i] )break;dp[f][j] = max ( dp[f][j], dp[!f][j - p * c[i]] * p );}}} for ( int i = 1;i <= sum;i ++ )if ( dp[f][i] >= m )return ! printf ( "%d", i ); return 0; }T3:排序問題
題目
九條可憐是一個(gè)熱愛思考的女孩子。
題目描述
九條可憐最近正在研究各種排序的性質(zhì),她發(fā)現(xiàn)了一種很有趣的排序方法: Gobo sort !
Gobo sort 的算法描述大致如下:
假設(shè)我們要對一個(gè)大小為 n 的數(shù)列 a 排序。
等概率隨機(jī)生成一個(gè)大小為 n 的排列 p 。
構(gòu)造一個(gè)大小為 n 的數(shù)列 b 滿足 bi=apib_i=a_{p_i}bi?=api??b,檢查 b 是否有序,如果 b 已經(jīng)有序了就結(jié)束算法,并返回 b ,不然返回步驟 2。
顯然這個(gè)算法的期望時(shí)間復(fù)雜度是 O(n×n!)O(n\times n!)O(n×n!)的,但是九條可憐驚奇的發(fā)現(xiàn),利用量子的神奇性質(zhì),在量子系統(tǒng)中,可以把這個(gè)算法的時(shí)間復(fù)雜度優(yōu)化到線性。
九條可憐對這個(gè)排序算法進(jìn)行了進(jìn)一步研究,她發(fā)現(xiàn)如果一個(gè)序列滿足一些性質(zhì),那么 Gobo sort 會(huì)很快計(jì)算出正確的結(jié)果。為了量化這個(gè)速度,她定義 Gobo sort 的執(zhí)行輪數(shù)是步驟 2 的執(zhí)行次數(shù)。
于是她就想到了這么一個(gè)問題:
現(xiàn)在有一個(gè)長度為 n 的序列 x ,九條可憐會(huì)在這個(gè)序列后面加入 m 個(gè)元素,每個(gè)元素是 [l,r] 內(nèi)的正整數(shù)。 她希望新的長度為 n+m 的序列執(zhí)行 Gobo sort 的期望執(zhí)行輪數(shù)盡量的多。她希望得到這個(gè)最多的期望輪數(shù)。
九條可憐很聰明,她很快就算出了答案,她希望和你核對一下,由于這個(gè)期望輪數(shù)實(shí)在是太大了,于是她只要求你輸出對 998244353 取模的結(jié)果。
輸入格式
第一行輸入一個(gè)整數(shù) T,表示數(shù)據(jù)組數(shù)。
接下來 2×T2 \times T2×T 行描述了 T 組數(shù)據(jù)。
每組數(shù)據(jù)分成兩行,第 1 行有四個(gè)正整數(shù) n,m,l,r,表示數(shù)列的長度和加入數(shù)字的個(gè)數(shù)和加入數(shù)字的范圍。 第 2 行有 n 個(gè)正整數(shù),第 i 個(gè)表示 xix_ixi?
輸出格式
輸出 TT 個(gè)整數(shù),表示答案。
輸入輸出樣例
輸入
2
3 3 1 2
1 3 4
3 3 5 7
1 3 4
輸出
180
720
說明/提示
樣例解釋
對于第一組數(shù)據(jù),我們可以添加 {1,2,2}\{1,2,2\}{1,2,2} 到序列的最末尾,使得這個(gè)序列變成 1 3 4 1 2 2 ,那么進(jìn)行一輪的成功概率是 1180\frac{1}{180}1801?,因此期望需要 180 輪。
對于第二組數(shù)據(jù),我們可以添加 {5,6,7}\{5,6,7\}{5,6,7} 到序列的最末尾,使得這個(gè)序列變成 1 3 4 5 6 7 ,那么進(jìn)行一輪的成功概率是 1720\frac{1}{720}7201? ,因此期望需要 720 輪。
數(shù)據(jù)范圍
對于 30% 的數(shù)據(jù), T≤10,n,m,l,r≤8T\leq 10 , n,m,l,r\leq 8T≤10,n,m,l,r≤8
對于 50% 的數(shù)據(jù), T≤300,n,m,l,r,ai≤300T\leq 300,n,m,l,r,a_i\leq 300T≤300,n,m,l,r,ai?≤300
對于 60% 的數(shù)據(jù),∑r?l+1≤107\sum{r-l+1}\leq 10^7∑r?l+1≤107
對于 70% 的數(shù)據(jù), ∑n≤2×105\sum{n} \leq 2\times 10^5∑n≤2×105
對于 90% 的數(shù)據(jù), m≤2×105m\leq 2\times 10^5m≤2×105
對于 100% 的數(shù)據(jù), T≤105,n≤2×105,m≤107,1≤l≤r≤109T\leq 10^5,n\leq 2\times 10^5,m\leq 10^7,1\leq l\leq r\leq 10^9T≤105,n≤2×105,m≤107,1≤l≤r≤109
題解
代碼中有一定的解釋,幫助大家理解,我真是太善良了
首先對于一個(gè)長度為nnn的序列,排序后變?yōu)椴煌男蛄械姆桨笖?shù)為n!n!n!
但是會(huì)有數(shù)字重復(fù)出現(xiàn),煮個(gè)栗子
雖然1的含義不一樣,但這個(gè)序列只能算一個(gè)
所以排序后不同的序列的方案數(shù)應(yīng)該為n!C1!C2!...Cx!\frac{n!}{C_1!C_2!...C_x!}C1?!C2?!...Cx?!n!?
CCC表示數(shù)字x出現(xiàn)的次數(shù)
但是這里又出現(xiàn)[l,r][l,r][l,r]的抉擇,我們觀察上面的式子,分子是固定的,如果要最后的結(jié)果盡量大,意味著分母要盡量小,我們知道階乘越往后乘得越大,所以這啟發(fā)我們盡量控制CCC的一致
首先對于不屬于[l,r][l,r][l,r]的數(shù)字就最先搞定,然后扔掉,不需要,接下來我們來算[l,r][l,r][l,r]區(qū)間的CCC的貢獻(xiàn)
我們考慮剛開始的nnn個(gè)數(shù)可能有一部分會(huì)出現(xiàn)在區(qū)間內(nèi),我們用樹狀來表示一下,看圖
hhh表示該數(shù)出現(xiàn)了hhh次,對應(yīng)在圖上就是樹狀的高度,因?yàn)橹荒芴?span id="ozvdkddzhkzd" class="katex--inline">mmm個(gè)數(shù),又要維持CCC的一致,我們就考慮二分這條線,什么線???那根黃線,看圖
紅色的部分表示填的數(shù)的區(qū)域,我們盡可能讓這個(gè)黃線下的可填數(shù)區(qū)域接近于mmm但不能超過,但我們不能保證mmm剛好填完,所以有可能有些區(qū)域上面會(huì)多一層,綠色部分代表一個(gè)數(shù)的高度,看圖
所以就劃分成了三種不同類型的樹狀,我們分別處理
1.長度超過答案黃線的,就是個(gè)數(shù)階乘
2.長度被我們拔高到等于黃線的,就是黃線高度階乘,用快速冪算多個(gè)的貢獻(xiàn)總和
3.長度在黃線之上多了僅僅一層綠帽子 ,就是高度+1+1+1階乘,用快速冪算多個(gè)的貢獻(xiàn)總和
最后涉及到除法,又有取模強(qiáng)迫我們用逆元,線性篩不推薦,時(shí)間空間都挺大,我們就老老實(shí)實(shí)地用快速冪求逆元,剛好模數(shù)是一個(gè)質(zhì)數(shù),搞費(fèi)馬小定理
CODE
ps:這個(gè)代碼可能會(huì)交出TLE,但是多交交幾遍,是AC的親測
#include <cstdio> #include <algorithm> using namespace std; #define int long long #define mod 998244353 #define MAXN 200005 #define MAXM 20000000 int T, n, m, l, r, cnt, tot, result, height; int a[MAXN], b[MAXN], fac[MAXM + 5];void prepare () {//預(yù)處理出階乘 fac[0] = 1;//必須初始化0,原因在后面 for ( int i = 1;i <= MAXM;i ++ )fac[i] = fac[i - 1] * i % mod; }int qkpow ( int x, int y ) {int ans = 1;while ( y ) {if ( y & 1 )ans = ans * x % mod;x = x * x % mod;y >>= 1;}return ans; }int inv ( int x ) {//求的是x的階乘的逆元 return qkpow ( fac[x], mod - 2 ); }int check ( int x ) {//統(tǒng)計(jì)[l,r]高度在x以下有多少個(gè)空可以選擇填數(shù)字 int sum = ( r - l + 1 - tot ) * x;//未出現(xiàn)在a數(shù)組里面的,這一豎列上一個(gè)數(shù)字都沒有 for ( int i = 1;i <= tot;i ++ )//出現(xiàn)在a數(shù)組里面的,統(tǒng)計(jì)上方空氣能填幾個(gè) if ( b[i] < x )sum += x - b[i];return sum; }void solve ( int L, int R ) {if ( L > R )return;int mid = ( L + R ) >> 1;if ( check ( mid ) <= m ) {height = mid;solve ( mid + 1, R );}elsesolve ( L, mid - 1 ); }signed main() {prepare();scanf ( "%lld", &T );while ( T -- ) {scanf ( "%lld %lld %lld %lld", &n, &m, &l, &r );for ( int i = 1;i <= n;i ++ )scanf ( "%lld", &a[i] );sort ( a + 1, a + n + 1 );a[n + 1] = -1;cnt = tot = 0;result = fac[n + m];for ( int i = 1;i <= n;i ++ ) {cnt ++;if ( a[i] != a[i + 1] ) { if ( l <= a[i] && a[i] <= r )//具體的數(shù)字對我們來說并不重要,我們只需要知道這個(gè)數(shù)字對應(yīng)的樹狀高度 b[++ tot] = cnt;elseresult = result * inv ( cnt ) % mod;cnt = 0;}}solve ( 0, MAXM );m -= check ( height );//剩下的m就填不滿一層,有些空會(huì)填,有些不會(huì),就特殊處理 for ( int i = 1;i <= tot;i ++ )if ( b[i] > height ) {//處理高于height的貢獻(xiàn) cnt ++;result = result * inv ( b[i] ) % mod;}// 處理在height基礎(chǔ)上多填一層的貢獻(xiàn) 處理被我們拔高到height高度的貢獻(xiàn) result = result * qkpow ( inv ( height + 1 ), m ) % mod * qkpow ( inv ( height ), r - l + 1 - m - cnt ) % mod;//注意這里的height可能等于0,如果不在上面初始化,答案就變成了0,你就從100pots變成了30pots printf ( "%lld\n", result );}return 0; }byebye~~
總結(jié)
以上是生活随笔為你收集整理的周末狂欢赛3(跳格子,英雄联盟,排序问题)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [费用流专题]Going Home,Mi
- 下一篇: [费用流]数字配对,新生舞会