加载中...

2022ICPC杭州(ACK)

A

\(exgcd\)

\(exgcd(a,b,x,y)\)\(a,b\)已知,用于求解\(ax + by = gcd(a,b)\)中的某一组解 \(x,y\);而求\(ax + by = k * gcd(a,b)\) 的解,只需要将 \(exgcd(a,b,x,y)\) 求出的\(x,y\) 同时乘上 \(k\) 即可。

具体题解:
pEnn724.jpg

code

C

被复杂题意包装起来的01背包。

简化一下题意就是:有\(n\)个物品,背包体积为\(k\),第\(i\)个物品的体积为\(p[i]\),且有\(p[i]\)种价值,其中只有一种价值对应“全部升级”(价值为\(w[i][p[i]]\)),剩下\(p[i]-1\)种价值对应“部分升级”(价值对应\(w[i][1到p[i]-1]\))。可以选择至多一个物品“部分升级”,其他必须为“全部升级”。设选取的“全部升级”的物品总体积为\(sum\),则“部分升级”物品的价值为\(w[i][k-sum]\)。求可获最大价值。

可以将物品的\(p[i]\)个价值看做:物品的体积为\(j\)时(\(j\in [1,p[i]]\)),价值为\(w[i][j]\)(可以证明这种定义方式与题意等价)。这样,就规定选取的物品存在“部分升级”时,总价值必须恰好为\(k\)。因此在初始化\(dp\)数组时必须为\(-INF\)(对于未规定选取恰好体积时初始化为\(0\))。

特点在于\(p[i]<=10\),且至多只能有一个“部分升级”的物品。所以状态可设置为:

\(dp[i][j][0/1]\):考虑前\(i\)个物品,选取物品的总体积为\(j\),且选了\(0/1\)个“部分升级”的物品,最大总价值。

可以直接暴力枚举“部分升级”物品的所有价值并转移,转移时对于第\(i\)种物品,考虑\(3\)种情况即可:

  1. 不选第\(i\)个物品(不代表真的不选,而是作为题中\(sum>k\)的那部分,价值为 \(0\) 地选择该物品,相当于不选。这里容易混淆)-> 从前缀的状态转移
  2. \(i\)个物品“全部升级” -> “部分升级”的\(0/1\)状态均能转移
  3. \(i\)个物品“部分升级” -> 由于最多只能选一个,则只能从已选“部分升级”的 \(0\) 状态转移

注意当\(k\)特别大时,所有物品不能装满背包,这时所有物品必须均为“全部升级”状态。而\(dp\)只处理了选取恰好体积的情况,故需要特判\(k\)很大的情况。(如果不特判,而是采用枚举\(dp[n][0到m][0/1]\)的方式更新答案,则会有一种情况导致错误:某个物品“部分升级”比“全部升级”的价值更大,导致对这个物品进行选择时,在背包体积足够时,选了该物品“部分升级”的情况。虽然这样的情况答案更优,但却是不合法的,因为在背包体积足够的情况下,所有物品必须“全部升级”。具体见WA on 7)

可以倒序枚举体积,省去01背包\(dp\)数组中物品个数的那一维。

具体实现见代码

复杂度\(O(nk*10)\)

ACcode

WA on 7

K

字典树

考虑逆序对的贡献是怎样产生的。

分析后可发现,逆序对产生的方式有两种:

  1. 两个字符串的前\(i-1\)个字符相同,第\(i\)个字符不同
  2. 一个字符串是另一个字符串的前缀

\(f[x][y]\)表示在给定的字符串序列中,\((str1,str2)\)对的数量,其中\((str1,str2)\)满足:

  1. \(str1\)\(str2\) 之前
  2. 存在一个位置 \(i\) ,使得\(str1[1到i-1]==str2[1到i-1]\)
  3. \(str1[i]==x\),\(str2[i]==y\)\(x,y\)表示字符。

则 $ans1 = $

\[ \sum_{seq[x]>seq[y]}f[x][y] \]

其中\(seq[x]\)为字符\(x\)在当前给定的字母表中的位置。

计算\(ans2\):在插入某个字符串\(str\)前,用这个字符串跑一遍字典树,若可到\(str\)的末尾,则看其末尾之后的前缀数量,这些字符串都可以使得\(str\)是它们的真前缀,自然和\(str\)构成逆序对。对于每个字符串,在插入前做这样的统计即可。注意走不到末尾时不能作统计,具体实现见代码。

code

posted @ 2025-02-05 21:29  jxs123  阅读(49)  评论(0)    收藏  举报